dbt Operations & Testing Playbook¶
Operating Principles¶
Keep dbt operations boring by standardizing how jobs run, how failures alert, and which tests guard each layer. Treat runs as production software pipelines - even if analysts write the SQL.
๐ Run Vocabulary
- Development: local, iterative,
dbt build --select my_model+ - Pre-Prod: automated validation on feature branches or staging datasets
- Production: scheduled jobs that own SLAs and downstream contracts
Run Types & Commands¶
| Scenario | Trigger | dbt Command(s) | Scope / Notes |
|---|---|---|---|
| Local development | Developer CLI / IDE | dbt build --select my_model+ |
Fast feedback on a model plus dependencies. |
| Pull-request (Slim CI) | CI runner | dbt build --select state:modified+ |
Touch only changed models + children, upload artifacts for review. |
| Scheduled production | Orchestrator | dbt build --select tag:daily or dbt build |
Full slices aligned to SLAs, rely on stored state for performance. |
| Backfill / replay | Manual CLI / job | dbt run --select fact_orders --vars '{start_date: "..."}' |
Recompute historical windows or recover from upstream issues. |
Document selectors, targets, threads, and variables for each scenario so operators rerun them consistently.
Testing Ladder¶
๐จ Ship Nothing With Failing Tests
CI pipelines and scheduled jobs must fail fast on any broken test. Production deployments without a green dbt test (or dbt build) are not allowed.
[!tip] ๐ก Testing Tactic
- Hit sources hard: Saturate staging/source models with not_null, unique, freshness, and schema-conformance tests so bad data is blocked before it propagates.
- Guard dimensions & facts: In the ADS/Gold layers (dimensions & facts), prioritize relationship tests, contracts, and business constraints to ensure metrics stay trustworthy.
1. Built-In Data Quality¶
- Saturate staging and ADS/Gold models with
not_nullanduniqueon natural or surrogate keys; only add these tests to intermediate models when they are high-risk models. - Use
relationshipsto enforce referential integrity between Gold-layer dimension & fact models. - Attach
accepted_valuesto enums and status fields to prevent silent drift.
2. Business Logic, Anomaly Tests & Freshness¶
- Store reusable custom tests in
tests/generic/(e.g.,test_positive_amounts.sql). - Capture scenario-specific checks via singular tests (SQL queries that return zero rows).
- Parameterize tests so new models inherit the logic automatically by referencing macros (see DRY - Don't Repeat Yourself for patterns).
- Configure
freshnessblocks per critical source with warn/error thresholds (e.g., warn after 18h, error after 26h).
Test Coverage Matrix¶
| Layer | Core Tests |
|---|---|
| Staging | not_null, unique, accepted_values, source-freshness |
| Intermediate (only if materialized) | Minimize tests in this layer. Only apply checks on high-risk models and during development |
| ADS | Key uniqueness and relationship depth |
| Gold (Dims/Facts) | Contracts, metric-specific assertions, dimensional constraints (e.g., Type 2 checks) |
Intermediate models that remain ephemeral should not accumulate dedicated test suites - lean on staging coverage upstream and ADS/Gold constraints downstream.
Lineage & Metadata Visibility¶
- Publish
dbt docs generate(HTML or JSON artifacts) every production deployment so the documented DAG, schema catalog, and test results stay current. - Feed
manifest.jsonandrun_results.jsoninto your data catalog or lineage tooling so business users can trace dependencies without reading SQL.
Performance & Cost Observability¶
- Prefer incremental models for large tables to avoid full reloads; ensure
is_incremental()filters limit processing to new partitions. - Profile slow queries (warehouse query plan, execution stats) and refactor heavy constructs (e.g.,
COUNT DISTINCT) into pre-aggregations when needed. - Review materialization choices periodically - ephemeral chains are great for small datasets but promoting high-cost intermediates to tables can cut runtime and spend.