Go home
Menu

How I keep dbt Core deployments boring in production

I keep dbt Core deployments boring with one short deployment record: state reference, selector, target, changed nodes, and promotion result before production moves.

· 4 min read by Berhan Turkkaynagi

A dbt deploy is easiest to trust when another engineer can tell me exactly what will run before production moves.

For me, this is the upstream counterpart to my BI release checklist: one compact artifact that makes scope, approval, and rollback legible before a business-critical number changes.

The failure mode I care about is not only a red job. It is a green promotion nobody can explain after a business-critical model changes.

That is why I keep the state reference, selector, target, changed nodes, and promotion result visible in one deployment note. If those details disappear behind wrappers or tribal memory, the deploy can still go green and still be hard to trust.

Problem

A dbt Core deploy can look fine in a pull request and still be hard to trust on its way to production.

SQL review passes. Tests are green. The pipeline UI says a job ran. I still need to know which production manifest I compared against, which selector will run, which target proved the change, and whether production promotion reuses that same logic or disappears behind a different wrapper.

If those answers are fuzzy, the failure mode is not just a red job. It is a production promotion nobody can explain when a business-critical model changes under time pressure.

Default approach

  • Keep one production manifest or state artifact available to CI so changed-node selection is based on a known production reference, not a guess.
  • Use one explicit selector for the change set and its downstream blast radius, then carry that selector into the deployment summary.
  • Keep environment targets intentional and easy to inspect so CI, staging, and production do not quietly diverge.
  • Prove the changed selection in a non-production target first, then promote with the same selector and state logic instead of inventing a second deployment path.
  • Attach one short deployment summary that shows the state reference, selector, target, changed nodes, and approval or promotion result.

If another engineer cannot explain what will run before the deploy starts, the workflow is still too opaque. I care more about an inspectable deploy than one more clever wrapper.

Example

Imagine a pull request that changes fct_revenue and one downstream finance mart.

The CI step I want visible is short:

dbt build --select state:modified+ --state <prod-artifacts> --target ci

The command is short, but the deployment summary is what earns trust:

FieldValue
PR#284
Changed modelfct_revenue
Downstream impactmart_finance_revenue
State referencemanifest.json from the last successful production deploy
Selectorstate:modified+
Targetci
Changed nodesfct_revenue mart_finance_revenue
Approvalchanged-node build reviewed after ci run passed
Production promotionreused the same selector and state logic
Resultpromoted without widening scope in production

That gives me enough context to approve production promotion.

I can see the production reference, selector, target, changed nodes, and approval path in one place. Most important, production promotion reused the same selection logic instead of inventing a second path at the promotion boundary.

If the same pull request had a green CI badge but no visible state reference, no selector, and no clear note about production promotion, I would still treat it as fragile. A green run is not the same as an explainable deploy.

If the deployment note is explicit and a run still goes wrong, I move to the observability signals that name the failed boundary to see whether the missed cutoff is recoverable before I open The incident note template I wish every analytics team used.

Tradeoffs

  • Breaks when: the production manifest or state artifact is missing, stale, or hard to retrieve → Mitigation: publish the last-known production artifacts from CI and make the state reference part of the default deployment record.
  • Breaks when: dev, CI, and production targets drift in ways the deployment note does not surface → Mitigation: keep target configuration explicit, review the target assumptions in the same place as the dbt invocation, and avoid hidden environment-specific behavior.
  • Breaks when: state:modified+ hides a wider blast radius on a business-critical model → Mitigation: widen the selector deliberately for critical paths and make the extra scope an explicit deployment choice, not a surprise after promotion.
  • Breaks when: CI wrappers make dbt feel automated but nobody can tell which command, selector, or artifact actually ran → Mitigation: expose the exact dbt invocation and artifact references in the deployment summary so the run stays inspectable.

Close

Next step: For one business-critical dbt model, write the deployment summary you want to see before its next production promotion: state reference, selector, target, changed nodes, and approval.

The promotion is easier to trust when the green run can be tied back to the manifest, selector, target, changed nodes, and approval without archaeology.