What you will be able to do
- Set Compare changes against to This Job on a deploy job or merge job, and know what each job type uses by default
- Explain which run a self-deferring job uses as its baseline, and how that differs from deferring to an environment
- Use state-based selectors in a self-deferring job without hitting the missing-artifact and zero-models traps
Key concept
Self-deferral — A job setting that makes the job's own most recent successful run the baseline for state comparison. It replaces a separate environment or job as that baseline. The artifacts from that earlier run tell dbt what changed and where to find anything the current run does not build.
1.The Compare changes against setting and its defaults
Any job that selects by state needs a baseline: artifacts from an earlier run that record what the project looked like then. Self-deferral takes that baseline from the job's own history. The job does not look at a production environment or some other job. It looks back at its own last successful run and compares against that.
You set this on the job, under Compare changes against, which has three choices: No deferral, an environment, or the job itself. On a deploy job, the self option is called This Job and appears in the optional Advanced settings. On a merge job, the same setting appears in Execution settings, and selecting This job is described as self-deferral.
The two job types start from opposite defaults. A deploy job starts at No deferral, so a scheduled job compares against nothing until someone picks an environment or This Job. A merge job starts out deferring to the environment it was created in. Its default command, dbt build --select state:modified+, depends on that: state comparison only works when a comparison target is selected. So on a merge job, choosing self-deferral moves away from a working default. On a deploy job, it fills a setting that was empty.
Checkpoint 1 of 6· Check yourself
A scheduled deploy job should compare each run's code with the code from its own previous successful run. Which configuration does that?
This Job is the self-deferral option. Choosing Environment compares against that environment's deploy jobs, No deferral compares against nothing, and dbt State is a separate node-reuse feature.
“Select either Environment or This Job to let dbt know what it should compare the changes against.”Source: docs.getdbt.com
Checkpoint 2 of 6· Exam question
In a dbt Cloud CI job's execution settings, what does selecting 'This job (self)' as the deferral target actually configure?
Correct answer: A — The job compares each new run's state against the most recent successful run of that same CI job, instead of against a separate production job or environment.
- A. Correct: self-deferral makes the job diff its current run against the manifest produced by its own most recent successful run, rather than pulling state from a separate job or environment such as production.
- B. Selecting a deferral target, including self, still enables `state:modified+` style incremental selection; skipping comparison and building everything happens only when no deferral target is configured at all.
- C. Development environments do not carry a deferral setting that propagates to deployment jobs; deferral is configured per job or environment for deployment jobs specifically, not inherited from the development environment.
- D. dbt Cloud resolves the deferred artifact automatically from the configured target when the run starts; it does not pause a CI run to request manual approval of which upstream job to defer to.
2.Which run a self-deferring job compares against
Deferral always needs a manifest from an earlier dbt invocation. On the command line, you pass that manifest's location with --state. In a job, the Compare changes against setting decides whose artifacts dbt fetches. With self-deferral, dbt takes the artifacts from the job's own most recent successful run. Runs that failed are ignored, and the baseline is the last run that succeeded.
Deferring to an environment works at a wider scope. dbt reads the manifest from the last successful run of any deploy job in that environment. Because every job there counts, the representation dbt compares against is the newest one available. That is why environment deferral is called the more efficient and more accurate choice for a comparison against production. Job deferral, including deferral to the job itself, is narrower: it compares against the code that this one job last ran successfully. In older dbt versions, a specific job was the only thing you could defer to. Choose self-deferral when the question is "what changed since this job last succeeded" rather than "what differs from production". The broader choice gets its own lesson: [when to use which type of job deferral](lesson:4.11).
| Option | Baseline dbt compares against |
|---|---|
| No deferral | None. This is the deploy job default |
| Environment | The manifest.json of the last successful deploy job run in the deferred environment, considering all deploy jobs there |
| This Job | The project code from this job's own last successful run |
References resolve by the usual rules from [deferral to other environments](lesson:3.8). The state manifest only replaces the target namespace for a node that is outside the selection and does not exist in the database. The --favor-state flag changes the second condition. A self-deferring job builds into its own schema run after run, so most unselected upstream models are already there.
Checkpoint 3 of 6· Check yourself
A self-deferring job runs dbt build --select state:modified+. One unmodified upstream model is not selected, but its table already exists in the job's target schema, and --favor-state is not used. Where does ref() to that model resolve?
Without --favor-state, deferral swaps in the state manifest only for nodes that are unselected and missing from the database. This relation exists, so the normal target namespace is used.
“It doesn’t exist in the database (or --favor-state is used).”Source: docs.getdbt.com
Checkpoint 4 of 6· Exam question
A CI job has Advanced CI's 'Compare changes' enabled and its deferral set to self. Data comparisons between the PR and the deferred run consistently fail even though both runs complete successfully. The production warehouse and the CI job's warehouse connection point at two different database hosts. What is the most likely explanation?
Correct answer: A — Compare changes requires both the PR run and the deferred run to query objects on the same database host, so pointing the CI connection at a different host than the deferred run breaks the row-level comparison.
- A. Correct: Compare changes needs to query the deferred run's objects to diff row and column data against the PR's build, which only works if both live on the same database host or connection; a mismatched host breaks that lookup regardless of the deferral target chosen.
- B. Advanced CI does not restrict comparisons by how the deferred run was triggered; a self-deferred job can compare against a prior PR run or a scheduled run equally, so trigger type is not the failure cause here.
- C. Compare changes evaluates actual data differences such as row counts and column-level changes between the two builds, not just documentation metadata, so this description of its scope is incorrect.
- D. Thread count controls how many models run concurrently within a single job and has no bearing on whether Compare changes can locate and diff objects across two database hosts.
3.Selectors that compare a job with its previous run
Self-deferral matters most for selectors that ask what changed since the last run. Source freshness is the clearest example. When the comparison points at a job, dbt pulls that job's artifacts from its most recent successful run and uses them to find which sources are fresh. source_status:fresher+ then builds only the sources with newer data, plus everything downstream of them.
# You can also set the DBT_ENGINE_STATE environment variable instead of the --state flag.
dbt source freshness # must be run again to compare current to previous state
dbt build --select "source_status:fresher+" --state path/to/prod/artifactsThere is a catch. The comparison needs a sources.json artifact in both the previous state and the current one. In a self-deferring job, both states come from the same job, so every run has to execute dbt source freshness. Suppose the job only started running freshness today. Its last successful run has no sources.json, so there is nothing to compare against.
Checkpoint 5 of 6· Fill the gap
A self-deferring job should rebuild only models downstream of sources that received new data since its last run. Which selector completes the command?
# You can also set the DBT_ENGINE_STATE environment variable instead of the --state flag.
dbt source freshness # must be run again to compare current to previous state
dbt build --select " ? " --state path/to/prod/artifactssource_status:fresher+ compares the current sources.json with the previous one and selects fresher sources and their children. state:modified+ compares code, not data freshness.
Result selectors also look back at the previous run. result:<status> selects nodes by how they finished last time. You can combine it with state:modified+ in one invocation, which picks up whatever errored previously plus anything new or changed.
dbt run --select "result:<status>+" state:modified+ --defer --state ./<dbt-artifact-path>state:modified on a scheduled job is where self-deferral can mislead you. If nobody changed the project since the last deferred run, nothing counts as modified. The run can then finish successfully while building zero models. A nightly job that defers to itself and selects only state:modified+ reports success every night the code stays the same, even though it rebuilt nothing.
Checkpoint 6 of 6· Exam question
Which of the following statements about a CI job configured with self-deferral are accurate? (Select all that apply.)(Select 3)
Correct answers: A, B, D — It compares state against the same job's most recent successful run rather than a separate production job or environment.; It requires that the job has completed at least one successful run before `state:modified+` has a manifest to diff against.; It can produce stale-schema errors after a referenced pull request merges and dbt Cloud drops that PR's temporary schema.
- A. Correct: self-deferral is defined as diffing the current run against the job's own last successful run, in contrast to pointing at a separate job or environment such as production.
- B. Correct: without a prior successful run of the job, there is no manifest for `state:modified+` to compare against, so the first run under self-deferral has nothing to diff and cannot use incremental selection.
- C. Incorrect: dbt's guidance is the opposite — self-deferral is discouraged for production-facing CI pipelines because the referenced schema can be dropped once its originating pull request merges, and a dedicated production job is recommended instead.
- D. Correct: because self-deferral points at whichever PR run the job last completed, that PR's temporary schema being cleaned up after merge can leave later runs referencing objects that no longer exist.
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Every job type starts with Compare changes against set to No deferral, so self-deferral is always an opt-in on an empty setting.Why is that wrong?
Only deploy jobs default to No deferral. Merge jobs default to comparing against the environment they were created from, so self-deferral replaces that default.
Covered in The Compare changes against setting and its defaults
2.Setting dbt State to On is how a job compares against its own previous run.Why is that wrong?
dbt State is a separate option that reuses nodes whose logic and data have not changed. Self-deferral is set through Compare changes against.
Covered in The Compare changes against setting and its defaults
3.A self-deferring job compares against its most recent run, whatever that run's status was.Why is that wrong?
Job deferral uses the job's last successful run. Runs that did not succeed are never the baseline.
4.Adding dbt source freshness to today's run is enough for source_status:fresher+ to work in a self-deferring job.Why is that wrong?
Both the previous state and the current state need sources.json. The job's earlier successful run must also have run source freshness.
Covered in Selectors that compare a job with its previous run
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/deploy/deploy-jobsOfficial docs
“Compare changes against — By default, it’s set to No deferral.”
↩︎ The Compare changes against setting and its defaults“By considering all deploy jobs that run in the deferred environment, dbt will get a more accurate, latest project representation state.”
↩︎ Which run a self-deferring job compares against“Older versions of dbt only allow you to defer to a specific job instead of an environment.”
↩︎ Which run a self-deferring job compares against“can result in the job completing successfully with zero models built when no changes are detected since the last deferred run”
↩︎ Selectors that compare a job with its previous run“Deferral to a job compares state against the project code that was run in the deferred job's last successful run.”
↩︎ Exam trap 3“Select either Environment or This Job to let dbt know what it should compare the changes against.”
↩︎ Checkpoint - 2.https://docs.getdbt.com/docs/deploy/merge-jobsOfficial docs
“To change the default settings, you can select No deferral, This job for self-deferral, or choose a different environment.”
↩︎ The Compare changes against setting and its defaults“Importantly, state comparison can only happen when there is a deferred environment selected to compare state to.”
↩︎ The Compare changes against setting and its defaults“To change the default settings, you can select No deferral, This job for self-deferral, or choose a different environment.”
↩︎ Key concept“Compare changes against — By default, it's set to compare changes against the environment you created the job from.”
↩︎ Exam trap 1“dbt State — dbt State reuses nodes when their logic and data haven’t changed, avoiding unnecessary rebuilds.”
↩︎ Exam trap 2“Compare changes against — By default, it's set to compare changes against the environment you created the job from.”
↩︎ Prediction - 3.
“Defer requires a manifest from a previous dbt invocation.”
↩︎ Which run a self-deferring job compares against“It doesn’t exist in the database (or --favor-state is used).”
↩︎ Checkpoint - 4.
“When a job is selected, dbt will surface the artifacts from that job's most recent successful run.”
↩︎ Which run a self-deferring job compares against“Or plainly said, both job states need to run dbt source freshness.”
↩︎ Selectors that compare a job with its previous run“combined in a single invocation of dbt to capture errors from a previous run OR any new or modified models”
↩︎ Selectors that compare a job with its previous run“This requires both the previous and current states to have the sources.json artifact available.”
↩︎ Exam trap 4