CertSafari
    DBT Architect· Lessons

    Domain 4 · Lesson 26/39

    Choosing a deferral target for dbt jobs and development

    Understanding when to use which type of job deferral

    14 min read
    2.56% of exam
    6 sources
    Published 13 Oct 2026
    Docs as of 12 Oct 2026

    What you will be able to do

    • Explain how dbt resolves a ref when deferral is on, and why it uses only one environment per invocation
    • Choose between No deferral, This job (self) and another environment for a merge or CI job
    • Diagnose a CI failure caused by self-deferral and keep the comparison manifest fresh
    • Pick the right deferral mechanism outside platform jobs: the Studio IDE toggle, the platform CLI, defer-env-id, defer_to_target or a manual --state

    Key concept

    Deferral target — Deferral target: the environment, or the job's own last run, whose manifest dbt uses when it resolves references to models it is not building. The target decides which state dbt compares changes against and where unbuilt parents are read from.

    1.What deferral resolves, and in what order

    Deferral lets a job or a developer build only the models they changed. Upstream parents are not rebuilt; their references point at relations that already exist elsewhere. dbt does this by reading a manifest from another run and resolving ref() calls against it. Choosing a deferral type is really choosing which manifest that is. The wrong choice shows up as a model reading stale data, or as a run that fails because the relation it points at no longer exists.

    When deferral is on, dbt looks for a parent in a fixed order. A development version of the relation wins if one exists. Without one, dbt uses the staging environment's metadata. With no staging environment, it falls back to production. Only one environment is consulted per invocation, so a project with a staging environment never mixes staging and production parents in the same run. Passing --favor-state skips the first step and always resolves to the deferred environment, even when a development copy exists.

    Deferral applies only to nodes you did not select. A selected model is always built in your own target. An unselected parent is swapped for the state version only when it does not already exist in the database, or when --favor-state is set. That is why a reader of dev_alice.model_b can end up joined to prod.model_a. Mixed reads like this can also make tests such as relationships compare data across environments.

    Checkpoint 1 of 8· Check yourself

    A developer has an old copy of model_a in their development schema and runs model_b with deferral on. The project has both a staging and a production environment. Which model_a does dbt read?

    Checkpoint 2 of 8· Exam question

    A dbt Cloud CI job on Snowflake intermittently fails with an error about a relation that belonged to a pull request merged and closed three days earlier. The CI job's deferral setting is configured as "This job (self)" rather than a production deploy job. Which change fixes the failure?

    Sources12

    2.No deferral, self or an environment: the job-level choice

    A dbt platform job has three deferral settings. The Compare changes against setting on a merge job defaults to the environment the job was created from. You can change it to No deferral, to This job (self-deferral), or to a different environment. A CI job has the same setting, labelled Compare changes against an environment (Deferral), and it defaults to Production if you created one. The environment-level setup behind this is covered in [configuring environment deferral](lesson:3.8).

    Deferring to an environment is the default for good reason. The standard command for both job types is dbt build --select state:modified+, and state comparison needs a deferred environment to compare against. Pick an environment when the job should build only what changed relative to what that environment last applied. That is the normal case for CI and for continuous deployment on merge. One precondition applies: the environment must have at least one successful job run, or there is no manifest to compare against.

    No deferral takes away that baseline. It suits a job that should not depend on another run's state: a full rebuild, or a first run in an environment where nothing has succeeded yet. Change the command when you choose it, because state:modified+ has nothing to compare against without a deferred environment.

    This job (self) makes the job's own previous run the baseline, instead of an environment's. The details are in [configuring self-deferral](lesson:4.10). Self-deferral is a poor fit for CI, where each pull request builds into its own temporary schema.

    That failure is the main warning against self-deferral in CI. Each CI run writes into a temporary dbt_cloud_pr_ schema, so a CI job's last run is always some earlier pull request. If that PR has merged, its schema may already be gone when the next CI run starts. The fix is to defer to production rather than to self.

    Checkpoint 3 of 8· Check yourself

    A team creates a merge job and leaves the default command dbt build --select state:modified+, but sets deferral to No deferral. What goes wrong?

    Checkpoint 4 of 8· Exam question

    An environment does not have a defer-env-id explicitly set, and the project's environments include only a Production environment with no Staging environment defined. When a job in this project runs with deferral enabled, which environment supplies the comparison artifacts?

    Sources34

    3.Keeping the deferred environment's manifest current

    Built-in deferral targets an environment, not a particular job. When a CI job defers to Production, the manifest it compares against comes from the latest successful run of any job that updates artifacts there. If several jobs with different settings run in that environment, the CI comparison state can shift unpredictably. A deploy or merge that refreshes the manifest while other pull requests are still open can also make those runs pick up unrelated state:modified nodes, until the branches are updated.

    There are two fixes, used together. Developers merge or rebase the latest base branch into their pull request. The team adds a merge job in the environment the CI job defers to, which runs dbt parse --no-partial-parse (or dbt compile) straight after each merge, so the manifest updates without warehouse work. If the merge also starts a long dbt build, a separate merge-triggered parse-only job updates the manifest before that build finishes. Production state can also be supplied by a deploy job, but never by a CI job: deferral compares against the most recent successful production job, excluding CI jobs. CI design overall is covered in [setting up a CI job with deferral](lesson:4.1).

    Which deferral setting fits which situation
    SituationDeferral choiceReason
    CI job checking a pull requestProduction environment (the default)Compares PR code against what production last applied, so only modified code is checked
    Merge job doing continuous deploymentThe environment the job was created from (the default)Builds only edited models and their downstream dependents
    Job that must not depend on another run's stateNo deferralNo baseline is used, so replace state:modified+ with a full selection
    CI error naming a previous PR's schemaSwitch from This job (self) to productionThe earlier PR's temporary schema may have been dropped
    CI picks up unrelated state:modified nodesKeep deferring to the environment; add a merge job running dbt parse --no-partial-parse thereRefreshes the comparison manifest right after merges

    Checkpoint 5 of 8· Check yourself

    CI runs on open pull requests keep selecting models the developers never touched, soon after other PRs merge. The CI job defers to Production. What is the recommended fix?

    Checkpoint 6 of 8· Exam question

    A platform team on Enterprise+ wants to enable Advanced CI ("compare changes") on an existing CI job so pull requests show row and column-level data differences against production. Which of the following are true prerequisites or constraints they must confirm? (Select all that apply.)(Select 2)

    Sources431

    4.Deferral outside platform jobs: IDE, CLI and self-managed runs

    Deferral is not only a job setting. Where dbt runs decides which mechanism is available, and each one targets its environment differently:

    - Studio IDE: the Defer to staging/production toggle pulls the latest manifest from staging, or from production if there is no staging environment, and adds --defer to commands that accept it. - dbt platform CLI: deferral is on for every invocation, compared with production artifacts; --no-defer turns it off. - defer-env-id in the dbt-cloud block of dbt_project.yml: points the platform at a different environment, such as staging. Because it is manifest-based, it disables dbt State-powered state:* selectors. - defer_to_target in profiles.yml: for self-managed deployments with dbt State. It names the target that dbt State defers to; without it, every target defers to prod. - Manual --state / --defer-state: points dbt at a specific manifest.json that you supply.

    The IDE has one gotcha worth remembering. When a Staging environment exists, the IDE defers to it. If no deploy job has run there yet, defer does not work at all, even with a healthy production environment, because the metadata it needs does not exist yet. Run a deploy job in Staging first.

    defer_to_target lets a self-managed uat target defer to staging instead of prodyaml
    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: prod

    Manual deferral gives the most control, and it needs the most care. Both --defer and --state must be set, either as flags or as environment variables. Normally one manifest does both jobs: it is the baseline for state:modified and the place unbuilt parents are read from. Pass --defer-state as well to split them. For example, you can compare logical changes against one environment and fail over to the built relations of another.

    Checkpoint 7 of 8· Match them up

    Match each deferral mechanism to where it applies

    Tap a term, then the definition that fits it.

    Checkpoint 8 of 8· Fill the gap

    Which flag completes this manual deferred test run?

    dbt run --select [...] --defer --state path/to/artifacts
    dbt test --select [...]  ?  --state path/to/artifacts

    Sources1562

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.Self-deferral is a safe choice for a CI job, because the job always has its own last run to compare against.Why is that wrong?

      A CI job's last run built into an earlier pull request's temporary schema, which can be dropped once that PR merges. Defer to a production job run instead.

      Covered in No deferral, self or an environment: the job-level choice

    2. 2.A successful CI run can serve as the production state that later deferrals compare against.Why is that wrong?

      Deferral compares against the most recent successful production job, and CI jobs are excluded.

      Covered in Keeping the deferred environment's manifest current

    3. 3.On the dbt platform, set defer_to_target in profiles.yml to choose which environment a job defers to.Why is that wrong?

      defer_to_target is only for self-managed deployments. On the platform, deferral is configured in the environment and job settings.

      Covered in Deferral outside platform jobs: IDE, CLI and self-managed runs

    4. 4.Studio IDE defer will fall back to production when a Staging environment exists but has never had a deploy job run.Why is that wrong?

      If a Staging environment exists, the IDE needs a successful deploy job there. Until one runs, defer does not work.

      Covered in Deferral outside platform jobs: IDE, CLI and self-managed runs

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “Note that dbt only defers to one environment per invocation — either staging or production.”
      ↩︎ What deferral resolves, and in what order
      “Passing the --favor-state flag will always resolve refs using staging metadata if available; otherwise, it defaults to production metadata”
      ↩︎ What deferral resolves, and in what order
      “When using defer, it compares artifacts from the most recent successful production job, excluding CI jobs.”
      ↩︎ Keeping the deferred environment's manifest current
      “--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.”
      ↩︎ Deferral outside platform jobs: IDE, CLI and self-managed runs
      “Note that dbt only defers to one environment per invocation — either staging or production.”
      ↩︎ Key concept
      “When using defer, it compares artifacts from the most recent successful production job, excluding CI jobs.”
      ↩︎ Exam trap 2
      “a Staging environment exists but no deploy job has run”
      ↩︎ Exam trap 4
      “If a development version of a deferred relation exists, dbt preferentially uses the development database location when resolving the reference.”
      ↩︎ Checkpoint
    2. 2.
      “It doesn’t exist in the database (or --favor-state is used).”
      ↩︎ What deferral resolves, and in what order
      “Tests that depend on multiple parents (for example, relationships), may run across environments.”
      ↩︎ What deferral resolves, and in what order
      “If --defer-state is not specified, deferral will use the manifest supplied to --state.”
      ↩︎ Deferral outside platform jobs: IDE, CLI and self-managed runs
      “Deferral requires both --defer and --state to be set”
      ↩︎ Deferral outside platform jobs: IDE, CLI and self-managed runs
    3. 3.
      “To change the default settings, you can select No deferral, This job for self-deferral, or choose a different environment.”
      ↩︎ No deferral, self or an environment: the job-level choice
      “compare changes against the environment you created the job from”
      ↩︎ No deferral, self or an environment: the job-level choice
      “For deferral (which is the default), make sure there has been at least one successful job run in the environment you defer to.”
      ↩︎ No deferral, self or an environment: the job-level choice
      “run dbt compile or, to avoid warehouse work entirely, dbt parse --no-partial-parse in a dedicated environment”
      ↩︎ Keeping the deferred environment's manifest current
      “Importantly, state comparison can only happen when there is a deferred environment selected to compare state to.”
      ↩︎ Checkpoint
    4. 4.
      “To fix this issue, select a production job run to defer to instead of self.”
      ↩︎ No deferral, self or an environment: the job-level choice
      “The latest successful run in the environment can come from any job that updates artifacts there.”
      ↩︎ Keeping the deferred environment's manifest current
      “Built-in deferral targets an environment, not a hand-picked job ID.”
      ↩︎ Keeping the deferred environment's manifest current
      “To fix this issue, select a production job run to defer to instead of self.”
      ↩︎ Exam trap 1
      “this is usually an indicator that you are not using a production job for your deferral and are instead using self.”
      ↩︎ Prediction
    5. 5.
      “If you set it, dbt State-powered state:* selectors are disabled.”
      ↩︎ Deferral outside platform jobs: IDE, CLI and self-managed runs
      “To defer to an environment other than the default (for example, staging), add defer-env-id to the dbt-cloud block in dbt_project.yml.”
      ↩︎ Checkpoint
    6. 6.
      “This configuration applies to self-managed dbt deployments.”
      ↩︎ Deferral outside platform jobs: IDE, CLI and self-managed runs
      “deferral is configured through your environment settings in the UI.”
      ↩︎ Exam trap 3

    Ready to test yourself?

    Practise the 9 questions on this subdomain.

    Spotted a mistake, or was something unclear? Tell us.