Running a full build of every model on each CI run is slow and expensive. dbt's state and defer features look at the most recent run, execute only the diff, and safely resolve unselected dependencies to existing production tables — making CI both stable and fast.
This article is based on the official documentation and walks through selector behaviors that show up on the exam, plus common CI design pitfalls. We are careful to call out areas that depend on your environment or dbt version.
dbt's state looks at artifacts produced by a previous run (typically manifest.json and friends) and compares them against the current repo state to detect changes. defer takes any dependencies you did not include in the build target and resolves them to existing relations (usually in production).
Together, this lets CI run only the changed models and their downstream impact while safely delegating upstream references to production — dramatically cutting both wait time and resource consumption.
state + defer flow in CI
Minimal command example
dbt build \
--state ./artifacts/prod \
--defer \
--select state:modified+state compares against the previous run's artifacts to determine which nodes are new or modified. Typical comparison targets include model SQL, config values that affect the model body, and test definitions. Macro changes can ripple widely, so be aware that related nodes may be marked as modified.
Selectors control which diff you run. In particular, a trailing plus includes children (downstream) and a leading plus includes parents (upstream) — intuitive once you know it, but a favorite exam question, so lock it in.
| Selector | Scope | Primary use | Notes |
|---|---|---|---|
| state:modified | Only the changed nodes | Run just the diff, narrowly targeted | Tests are implicitly included via build |
| state:new | Only newly added nodes | Validating freshly added models | Excludes existing nodes |
| state:modified+ | Changed nodes plus their descendants (downstream) | Validate downstream impact too | Useful for checking schema compatibility |
| +state:modified | Changed nodes plus their ancestors (upstream) | Rebuild dependencies from source down to the change | Use when upstream needs to be refreshed |
List the detected changes only (do not execute)
dbt ls --state ./artifacts/prod --select state:modifieddefer resolves ref and source references for any unselected dependency nodes to the existing relations recorded in the artifacts you pass via --state. Typically you point this at the full artifact set from the last successful production run.
This lets you build just the diff in CI's temporary schema without rebuilding upstream. But if the deferred-to relation does not exist, you will get a reference error — so the assumption is that the target actually exists in production.
Build only the diff in the CI target, using defer
dbt build \
--target ci \
--state ./artifacts/prod \
--defer \
--select state:modified+In practice, you keep the target/ directory from production (or at least manifest.json) somewhere CI can always reach it. The workflow: on successful production jobs, push the artifacts to storage; in CI, pull them and hand the path to --state.
On dbt Cloud, you can defer to Production via UI settings and Cloud handles artifact resolution internally. On dbt Core you provide the artifacts yourself.
Conceptual GitHub Actions example
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Restore prod artifacts
run: |
mkdir -p artifacts/prod
aws s3 cp s3://my-bucket/dbt/prod/last_success/ ./artifacts/prod --recursive
- name: Install dbt
run: pip install dbt-core dbt-bigquery # example: match your target
- name: Build changed nodes with deferral
run: |
dbt build \
--profiles-dir . \
--target ci \
--state ./artifacts/prod \
--defer \
--select state:modified+If you let defer hide schema-breaking changes (dropped columns, type changes), child models will fail at runtime. Default to state:modified+ so descendants of changed nodes run, and widen to +state:modified+ when a breaking change is suspected.
For incremental models, deferring unselected upstream to production does not guarantee the new-vs-old data diff is what you intended. For critical paths, consider a full refresh or a scoped recomputation.
Validate changed models and their tests together
dbt build \
--state ./artifacts/prod \
--defer \
--select state:modified+The exam often tests the meaning of state selectors, the direction of +, and the purpose and preconditions of defer (referencing an existing relation). Be ready for CI scenario questions, too — you should be able to write the correct command from memory.
Commands worth memorizing
dbt ls --state ./artifacts/prod --select state:modified
dbt build --state ./artifacts/prod --defer --select state:modified+
dbt build --state ./artifacts/prod --defer --select +state:modified+Analytics Engineer
問題 1
Upstream tables exist in production. In CI you want to run only the changed models and their downstream, while resolving unselected references to production. Which command is most appropriate?
正解: A
The requirements are diff detection plus reference resolution to production. A is correct: it combines --state and --defer with state:modified+ (changed nodes plus downstream). B has no defer. C includes upstream, which is the opposite of what we want. D only matches new nodes, which does not meet the requirement.
What artifacts do I need to provide for state?
At minimum, you need the previous run's target/ directory containing manifest.json. In practice, archive target/ on successful production runs and point CI's --state at that directory.
Is defer different between dbt Cloud and dbt Core?
The mechanism is the same, but Cloud lets you defer to Production via environment settings and handles artifact retrieval internally. With Core, you specify --defer and --state yourself and implement artifact storage and distribution in your pipeline.
When I change a macro, how far does state:modified propagate?
Macro changes may be flagged on any node whose compilation depends on the macro. The impact can be broad, so right after a change, verify the selection with dbt ls --state ... and widen the selection as needed.
Practice with certification-focused question sets
無料で問題を解いてみるNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
dbt Models: SQL-Defined Transformation Units (2026)
Model fundamentals — SELECT-based definitions, naming, refs,...
dbt Analytics Engineering Exam: Complete Guide (2026)
Pass the AE Certification — scope, weighting, sample questio...
dbt Cloud vs dbt Core: Feature & Cost Comparison (2026)
Honest comparison of dbt Cloud vs. dbt Core — IDE, scheduler...
dbt Project Structure: models/seeds/macros Layout (2026)
Recommended dbt project layout — models, seeds, macros, snap...
dbt_project.yml Explained: Every Config (2026)
Every dbt_project.yml setting that matters — paths, vars, ma...