A strong fit if
This consulting work is a strong fit when…
No tests that mean anything
No layering, just one file
Brittle runs
Lineage nobody trusts

Audit, implement or refactor dbt Core and dbt Cloud projects across Snowflake and BigQuery. Improve model structure, testing, contracts, CI, documentation and release confidence without rebuilding everything from scratch.
A strong fit if
No tests that mean anything
No layering, just one file
Brittle runs
Lineage nobody trusts


Probably not a fit if
The platform and delivery constraint are still completely unknown.
The work needs permanent on-call coverage or an unrestricted backlog.

What changes
Choose the dbt problem that needs to change. Each service connects implementation to a reviewable output.
dbt project audits and health checks
Review project structure, model grain, tests, CI, documentation, performance and ownership, then prioritize the fixes.
dbt Core and dbt Cloud implementation
Set up or refactor projects, environments, jobs and pull request checks for the way your team ships changes.
Unit tests, contracts and data quality
Turn business assumptions into tests and explicit model interfaces that fail before a dashboard does.
Legacy SQL migration
Move stored procedures, views and repeated dashboard SQL into layered, reviewable dbt models.
Incremental model performance
Tune materializations, keys and warehouse usage around the actual data shape and update pattern.
Orchestration and project standards
Connect dbt to CI, Airflow or Dagster and document conventions the team can continue using.
Technical example
A common failure mode is a refund join that silently changes revenue. The revised model uses references, an explicit key, an enforced contract and a singular test that returns any broken rows.
models/marts/fct_revenue.sql (before)
-- models/marts/fct_revenue.sql (before) -- Grain: invoice_id. Source: raw.invoices joined to raw.refunds. -- Tests: not_null(invoice_id), unique(invoice_id). -- The reconciliation between fct_revenue and the GL runs in a -- spreadsheet. The gap is "explained" by a footnote the day before -- close. The dbt test suite does not catch the double-count. select i.invoice_id, i.amount, r.refund_amount from raw.invoices i left join raw.refunds r using (invoice_id)
models/marts/fct_revenue.sql (after)
-- models/marts/fct_revenue.sql (after)
{{ config(
materialized='incremental',
incremental_strategy='merge',
unique_key='invoice_id',
contract={'enforced': True},
on_schema_change='append_new_columns',
snowflake_warehouse='transforming_xs',
tags=['finance', 'marts']
) }}
with invoices as (select * from {{ ref('stg_invoices') }}),
refunds as (select * from {{ ref('stg_refunds') }})
select
i.invoice_id,
i.amount as gross_revenue,
coalesce(r.refund_amount, 0) as refund_amount,
i.amount - coalesce(r.refund_amount, 0) as net_revenue,
i.updated_at
from invoices i
left join refunds r using (invoice_id)
{% if is_incremental() %}
where i.updated_at > (select max(updated_at) from {{ this }})
{% endif %}
Reviewable delivery
Before sign-off, the project should show the model grain, dependencies and acceptance criteria alongside the pull request. Relevant tests should run successfully, documentation should describe the interface, and any remaining migration or performance risk should be explicit.
How we work
Use a defined project for one dbt outcome or recurring support for a backlog that keeps growing.
01
Northgrain works inside your team: models, contracts and pull requests in your repository, with a clear communication rhythm and handoff.
02
A scoped dbt build with a clear start, end, and handoff: a migration, a cleanup, or an audit with a prioritized roadmap your team can run.
Questions

Share the repository, the failure mode and what needs to change. We will reply with the most useful next step.