What you will be able to do
- Trace how dbt resolves a ref under deferral: development first, then staging, then production
- Prepare a deployment environment so it can serve as a deferral target
- Enable or disable deferral in the Studio IDE and the dbt platform CLI
- Point deferral at a specific environment with defer-env-id
- Configure deferral outside the dbt platform with --defer, --state and defer_to_target
Key concept
Deferral — Deferral lets dbt run only the nodes you selected. Any upstream ref you did not build resolves to the relation that already exists in another environment, located from that environment's manifest. On the dbt platform, that environment is Staging when one exists and Production otherwise.
1.How a deferred ref finds its parent
Deferral saves you from rebuilding a whole upstream DAG just to test one model. Say a developer edits model_b, which selects from {{ ref('model_a') }}, and their development schema dev_alice is empty. A plain dbt run --select "model_b" compiles to from dev_alice.model_a, and the query fails because that relation does not exist. Add deferral and the same ref compiles to prod.model_a, so the run succeeds without anyone building model_a first.
For each ref, dbt checks locations in a fixed order. A relation in your development schema wins. If there isn't one, dbt uses the parent's location as recorded in the staging environment's metadata. If there is no staging environment either, it uses the production environment's metadata. Each invocation defers to a single environment, never a mix of staging for some parents and production for others.
Two exceptions change this order. Passing --favor-state skips the first step: refs resolve from staging or production metadata even when a development relation exists. Ephemeral models are never deferred at all, because they compile inline into whatever references them. In the dbt platform, a ref is only deferred when the node is not among the selected nodes. A model you selected always builds in your own schema.
Checkpoint 1 of 8· Put it in order
Put the locations dbt tries, when deferral is on and no --favor-state is passed, in the order it tries them
- 1.The parent's location from the production environment's metadata
- 2.The parent's location from the staging environment's metadata
- 3.The relation in the developer's own development schema
Development comes first, then staging, and production is the last fallback. Only one of staging or production is used in any single invocation.
“If a development version doesn't exist, dbt uses the staging locations of parent relations based on metadata from the staging environment.”Source: docs.getdbt.com
Checkpoint 2 of 8· Exam question
A dbt Cloud project has both a 'Staging' environment and a 'Production' environment configured. A developer runs `dbt build --select model_a --defer` from the Studio IDE, and `model_a`'s upstream dependency `stg_orders` does not exist in the developer's own development schema. Which environment's build artifacts will dbt resolve `ref('stg_orders')` against?
Correct answer: A — dbt resolves the ref against the Staging environment's artifacts, since dbt prefers staging metadata over production whenever both exist and no dev build is present.
- A. This is correct. When a development version of a model is absent, dbt's deferral fallback order checks staging metadata before production, so a configured Staging environment takes precedence over Production for ref resolution.
- B. This is incorrect. Marking an environment as Production does not force dbt to ignore a configured staging preference; staging metadata is checked first in the fallback order when a development build is missing.
- C. This is incorrect. The `--defer` flag exists specifically to change how `ref()` and `source()` calls are resolved during compilation, pointing unbuilt nodes at deferred environment artifacts instead of the developer's own schema.
- D. This is incorrect. Deferral does not simply track whichever environment had the newest job; it follows a defined precedence of development build, then staging metadata, then production metadata.
2.What makes an environment a deferral target
Deferral reads artifacts from a deployment environment, so that environment has to be set up correctly first. Every deployment environment has a deployment type: General, Staging or Production. Creating these environments is covered in [creating deployment environments](lesson:3.5). For deferral, the type you choose decides whether the environment can be a target at all.
| Deployment type | How many per project | Role in default deferral |
|---|---|---|
| Production | 1 | Fallback target when no Staging environment exists |
| Staging | 1 | Preferred target whenever it is defined |
| General | Any number | Not chosen by default |
The Production environment checkbox in Environment Settings is the starting point. Only one deployment environment per project can carry it. That environment also needs at least one successful job run, because a run is what produces the manifest that deferral compares against. Not every run qualifies: dbt uses the most recent successful production job and ignores CI jobs.
Adding a Staging environment changes the default target straight away, and that can break things. Once a Staging environment exists, the Studio IDE looks for its artifacts first. If no deploy job has run there yet, there is no metadata to defer to, and defer in the IDE stops working until a deploy job succeeds in Staging. Teams add Staging to keep developers away from production data. Developers still get metadata-powered features like deferral, while the Production environment stays locked down with environment-level permissions.
Checkpoint 3 of 8· Check yourself
A team creates a new Staging environment on Monday to keep developers off production data. Deploy jobs are scheduled to start running there on Friday. What happens when developers use Defer to staging/production in the Studio IDE on Tuesday?
dbt prefers Staging as soon as it exists. It does not fall back to Production just because Staging has no artifacts yet, so defer fails until a deploy job runs in Staging.
“The defer feature in the Studio IDE won't work if a Staging environment exists but no deploy job has run.”Source: docs.getdbt.com
3.Turning deferral on in the Studio IDE and the platform CLI
The two development tools have opposite defaults. In the Studio IDE, deferral is opt-in: you toggle Defer to staging/production on the command bar. dbt then pulls the latest manifest from the staging or production environment and adds --defer to every command that accepts it. Start a branch with an empty development schema, edit one model and run dbt build -s state:modified, and only the edited model runs. Its refs resolve to staging or production.
The dbt platform CLI defers on every invocation automatically, comparing against production artifacts. To build a model's parents into your own schema instead, pass --no-defer. Automatic deferral only works if the CLI can tie your local project to a dbt platform project. That means dbt_project.yml must declare the project id that matches your dbt_cloud.yml.
dbt-cloud:
project-id: '654321'Checkpoint 4 of 8· Check yourself
A developer using the dbt platform CLI wants one run that builds a model's upstream parents into their own development schema instead of reading them from production. What do they do?
The platform CLI defers on every invocation by default, and --no-defer turns it off. The IDE toggle only affects the IDE. --favor-state pushes resolution further toward state, the opposite of what the developer wants.
“--defer is automatically enabled in the dbt platform CLI for all invocations, compared with production artifacts. You can disable it with the --no-defer flag.”Source: docs.getdbt.com
Checkpoint 5 of 8· Exam question
A dbt Cloud administrator wants automatic deferral to work correctly for a CI job that compares pull request changes against production. Which two conditions must be true for this to function? (Select two.)(Select 2)
Correct answers: A, B — One environment in the project must be explicitly marked as the Production environment in its environment settings.; The Production environment must have at least one successful deploy job run so that comparison artifacts exist.
- A. This is correct. dbt Cloud needs one environment explicitly flagged as Production so there is a canonical environment for CI jobs to compare pull request changes against by default.
- B. This is correct. Deferral compares against the most recent successful deploy job's artifacts, so without at least one completed deploy run in that environment there is nothing valid to defer to.
- C. This is incorrect. CI-job deferral is configured at the environment and job level in dbt Cloud settings; it does not depend on individual developers manually adding flags to their own local commands.
- D. This is incorrect. CI jobs commonly trigger on pull requests via a git provider webhook, and the trigger type chosen for the job is unrelated to whether deferral is correctly configured.
Sources1
4.Choosing the environment with defer-env-id
The Staging-then-Production default is only a default. You can defer to any environment by setting a defer-env-id key to that environment's id. Where you put the key determines which tools use it. In dbt_project.yml it applies to both the dbt platform CLI and the Studio IDE. In dbt_cloud.yml it applies only to the platform CLI. The file you choose decides whether IDE developers get the override.
context:
active-host: ...
active-project: ...
defer-env-id: '123456'Setting the key has a cost if your account uses dbt State. defer-env-id works from a manifest, so it turns off the dbt State-powered state:* selectors that compare each node against its own last execution. Without the key, dbt State defers to production by default. Add defer-env-id only when you actually need a different target, such as Staging.
Checkpoint 6 of 8· Fill the gap
Complete the dbt_project.yml block so that both the Studio IDE and the platform CLI defer to environment 123456.
dbt-cloud:
project-id: '654321'
? : '123456'defer-env-id under dbt-cloud in dbt_project.yml sets the deferral environment for both tools. defer_to_target is a profiles.yml setting for self-managed deployments.
Source: docs.getdbt.comCheckpoint 7 of 8· Exam question
In dbt Cloud, what does the `--favor-state` flag change about how `--defer` resolves `ref()` calls, compared to default deferral behavior?
Correct answer: A — It always resolves refs using the deferred environment's metadata, skipping the developer's own development build even when one already exists locally.
- A. This is correct. The `--favor-state` flag skips the normal check for a local development version of a node and always resolves refs against the deferred (staging or production) environment's metadata instead.
- B. This is incorrect. Default deferral already prefers staging metadata over production when staging is configured; `--favor-state` changes whether a local dev build is checked first, not the staging-versus-production preference.
- C. This is incorrect. `--favor-state` changes which artifacts are favored during ref resolution; it does not turn off deferral, and combining it with `--defer` is a normal, supported usage rather than a contradiction.
- D. This is incorrect. Deferral resolution is based on successful job run artifacts and configured environment preference, not on the modification timestamp of a project's `dbt_project.yml` file.
5.Deferral outside the dbt platform
Outside the dbt platform, nothing defers automatically. You have to supply both a manifest and the instruction to use it. --defer turns deferral on and --state points at the directory holding a previous run's manifest.json. Deferral needs both. Copy the artifacts from a production run into a local folder, then pass that folder on each command.
dbt run --select [...] --defer --state path/to/artifacts
dbt test --select [...] --defer --state path/to/artifactsEach flag has a matching environment variable: DBT_ENGINE_DEFER, DBT_ENGINE_STATE and DBT_ENGINE_DEFER_STATE. If a flag and its variable are both set, the flag wins. --defer-state is optional. It lets you compare state:modified against one manifest while deferring unbuilt parents to another. When you leave it out, deferral uses the --state manifest. That is usually what you want: compare against production and fall back to production.
Self-managed deployments with dbt State enabled have a third option: set defer_to_target in profiles.yml. It names the target that dbt State defers to, and when it is omitted every target defers to the one named prod. On the dbt platform this setting does nothing, because deferral there is configured on the environment. Without a manifest, dbt State guesses each parent's location by re-rendering database and schema names against that target. A generate_alias_name macro that varies by target is the riskiest case, since a wrong guess can corrupt data. If you have one, supply a manifest.json. For when to choose this setup over self-deferral or a CI job that defers, see [choosing a deferral type](lesson:4.11).
my_project:
outputs:
dev:
type: snowflake
# ... dev connection settings
staging:
type: snowflake
# ... staging connection settings
uat:
type: snowflake
# ... uat connection settings
defer_to_target: staging
prod:
type: snowflake
# ... prod connection settings
target: prodCheckpoint 8 of 8· Match them up
Match each self-managed setting to what it does
Tap a term, then the definition that fits it.
--defer and --state are the required pair. --defer-state splits the deferral manifest from the comparison manifest. defer_to_target is the dbt State profile setting.
“If --defer-state is not specified, deferral will use the manifest supplied to --state.”Source: docs.getdbt.com
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.With deferral on, the dbt platform always resolves unbuilt parents to Production.Why is that wrong?
If a Staging environment is defined, dbt prefers its metadata and only falls back to Production when there is no Staging environment.
Covered in How a deferred ref finds its parent
2.Setting defer-env-id in dbt_cloud.yml changes the deferral target for the Studio IDE too.Why is that wrong?
Only dbt_project.yml applies to both tools. dbt_cloud.yml is read by the dbt platform CLI alone.
Covered in Choosing the environment with defer-env-id
3.Passing --defer on its own is enough to defer in a self-managed run.Why is that wrong?
Deferral needs a manifest as well, so --state (or DBT_ENGINE_STATE) has to be set alongside --defer.
Covered in Deferral outside the dbt platform
4.Adding defer_to_target to profiles.yml changes which environment the dbt platform defers to.Why is that wrong?
defer_to_target is for self-managed deployments only. On the dbt platform, deferral is configured in the environment settings.
Covered in Deferral outside the dbt platform
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.https://docs.getdbt.com/docs/platform/about-deferOfficial docs
“Note that dbt only defers to one environment per invocation — either staging or production.”
↩︎ How a deferred ref finds its parent“Passing the --favor-state flag will always resolve refs using staging metadata if available”
↩︎ How a deferred ref finds its parent“You must select the Production environment checkbox in the Environment Settings page. This can be set for one deployment environment per dbt project.”
↩︎ What makes an environment a deferral target“When using defer, it compares artifacts from the most recent successful production job, excluding CI jobs.”
↩︎ What makes an environment a deferral target“To enable defer in the Studio IDE, toggle the Defer to staging/production button on the command bar.”
↩︎ Turning deferral on in the Studio IDE and the platform CLI“A dbt platform project id must be declared in your dbt_project.yml for automatic deferral”
↩︎ Turning deferral on in the Studio IDE and the platform CLI“(dbt platform CLI and Studio IDE) or dbt_cloud.yml (dbt platform CLI only) file”
↩︎ Choosing the environment with defer-env-id“dbt powers this by using a production manifest for comparison”
↩︎ Key concept“By default, dbt will prefer metadata from the project's "Staging" environment (if defined). Otherwise, it uses "Production."”
↩︎ Exam trap 1“(dbt platform CLI and Studio IDE) or dbt_cloud.yml (dbt platform CLI only) file”
↩︎ Exam trap 2“If a development version of a deferred relation exists, dbt preferentially uses the development database location when resolving the reference.”
↩︎ Prediction“If a development version doesn't exist, dbt uses the staging locations of parent relations based on metadata from the staging environment.”
↩︎ Checkpoint“The defer feature in the Studio IDE won't work if a Staging environment exists but no deploy job has run.”
↩︎ Checkpoint“--defer is automatically enabled in the dbt platform CLI for all invocations, compared with production artifacts. You can disable it with the --no-defer flag.”
↩︎ Checkpoint - 2.
“Ephemeral models are never deferred, since they serve as "passthroughs" for other ref calls.”
↩︎ How a deferred ref finds its parent“If you apply environment-specific limits in development but not in production, you may select more data than expected.”
↩︎ How a deferred ref finds its parent“Deferral requires both --defer and --state to be set, either by passing flags explicitly or by setting environment variables”
↩︎ Deferral outside the dbt platform“Deferral requires both --defer and --state to be set, either by passing flags explicitly or by setting environment variables”
↩︎ Exam trap 3“If --defer-state is not specified, deferral will use the manifest supplied to --state.”
↩︎ Checkpoint - 3.
“can have any number of General deployment environments, one Production deployment environment and one Staging deployment environment.”
↩︎ What makes an environment a deferral target - 4.
“Staging: Environment for working with production tools while limiting access to production data.”
↩︎ What makes an environment a deferral target - 5.
“defer-env-id is manifest-based. If you set it, dbt State-powered state:* selectors are disabled.”
↩︎ Choosing the environment with defer-env-id“By default, dbt State defers to your production environment.”
↩︎ Choosing the environment with defer-env-id - 6.
“If both the flag and env var are provided, the flag takes precedence.”
↩︎ Deferral outside the dbt platform - 7.
“When omitted, all targets defer to the target named prod.”
↩︎ Deferral outside the dbt platform“This scenario is the most likely to cause data corruption. If you have custom generate_alias_name logic, provide a manifest.json to guarantee accurate results.”
↩︎ Deferral outside the dbt platform“This configuration applies to self-managed dbt deployments. If you're using the dbt platform, deferral is configured through your environment settings in the UI.”
↩︎ Exam trap 4