Skip to main content

State-Aware Runs

Most scheduled dbt runs rebuild the whole project every night, including the models whose SQL, configuration, and input data have not changed since the last successful run. You pay your warehouse for that work every time, and you wait for it before anything downstream is ready.

State-aware runs remove that waste. Before a scheduled job executes, dbdeux proves which models would produce the same result as last time and skips exactly those, then reports what it skipped and why.

Nightly build - Production
State-aware runs onCompiling
State-aware run: reused 4 of 6 nodes (1 cloned) - 2 executed
This run
stg_orderschecking...
stg_customerschecking...
dim_customerschecking...
fct_orderschecking...
fct_order_itemschecking...
rpt_revenue_dailychecking...
State tab
Reused3 nodes
Cloned1 nodes
Rebuilt2 nodes
67%
Reuse rate
8.4m
Est. saved
17.9m
Full rebuild
Every model is checked against the last successful run of this environment. Anything that cannot be proven unchanged is rebuilt, so a state-aware run is never less correct than a full one.

How a Model Earns a Skip

A model is only skipped when dbdeux can prove nothing about it would change. Each run:

  1. Compiles the project, so every model's final SQL is known, not guessed from the file text
  2. Gives each model a fingerprint built from its compiled SQL, its resolved configuration, its target table, its parents' fingerprints, and, for sources, the last-modified time reported by your warehouse
  3. Compares that fingerprint against the baseline from this environment's last successful state-aware run
  4. Confirms the model's table or view still exists in the warehouse
  5. Skips the model only if both the fingerprint matches and the target is still there

Because a parent's fingerprint feeds into its children, changing one staging model correctly invalidates everything downstream of it. Nothing needs a list of "affected models" maintained by hand.

Tests are fingerprinted the same way. A test whose inputs are all provably unchanged does not need to run again to tell you the same thing.

Anything Unprovable Rebuilds

The rule that matters most: uncertainty always rebuilds. A model runs normally when its SQL is volatile (a current_timestamp() or a random value makes the result different each time), when it has hooks, when its materialization cannot be reused, when the warehouse cannot tell us whether a source moved, when the job uses flags such as full refresh or defer, or simply when there is no baseline yet.

If anything about the check itself goes wrong, the run degrades to an ordinary full run. State-aware execution can make a run cheaper. It cannot make a valid run fail, and it cannot hand you a stale table.

Missing Tables Restored, Not Rebuilt

A model whose fingerprint matches but whose table is missing from this environment does not have to be recomputed from scratch. dbdeux restores it by cloning from an environment that already has an identical version of it, usually production.

WarehouseHow the restore happens
SnowflakeZero-copy clone. A metadata operation, so it is effectively instant and costs no compute
Google BigQueryZero-copy table clone, with the same properties
DatabricksDeep clone. It does copy the data, but it still avoids re-running the transformation, and the copy stays valid if the original is later cleaned up

That is the difference between minutes of warehouse compute and a near-instant operation, and it is what makes a fresh staging environment cheap to stand up. Fingerprints are computed so that the same model logic over the same upstream data matches across environments, which is what allows production to act as the clone source. If a clone cannot be taken, the model is rebuilt normally and the reason is recorded.

What Your Warehouse Can Prove

Reuse is only ever as good as the metadata your warehouse exposes, so coverage comes in tiers rather than a yes or no. You do not have to work out which tier applies to you: the environment's State tab reads the warehouse that environment is actually connected to and states its capability in one line, such as "On Snowflake, unchanged models are skipped and missing tables are restored with a zero-copy clone." The tiers below are what those lines mean.

Warehouse coverage - ProductionState tab
SnowflakeFull reuse + restore
Freshness proof, zero-copy clone restore
Google BigQueryFull reuse + restore
Freshness proof, zero-copy clone restore
DatabricksFull reuse + restore
Freshness proof, deep clone restore
Amazon RedshiftProven reuse
Reuse for seed and model lineage
PostgreSQLProven reuse
Reuse for seed and model lineage
MotherDuckProven reuse
Reuse for seed and model lineage
Microsoft FabricProven reuse
Reuse for seed and model lineage
Azure SynapseProven reuse
Reuse for seed and model lineage
Amazon AthenaProven reuse
Reuse for seed and model lineage
Everything elseSafe fallback
Runs normally, nothing to configure
Full reuse + restoreYour warehouse reports when source data last moved, so any model can be proven unchanged, and a missing table is restored by clone instead of recomputed.
Proven reuseYour warehouse can confirm a table exists but not when its data last moved, so models built from seeds and other models are reused and anything fed by a source rebuilds.
Safe fallbackNo reuse is attempted, and the run does exactly what it would have done anyway. There is nothing to switch off and nothing to lose.
Coverage only decides how much a run can save. A warehouse that cannot prove anything builds exactly what it would have built without state-aware runs.

Full reuse and restore applies where the warehouse reports when a table's data last changed. That is what lets a model fed by a raw source be proven unchanged, and it is the tier where a missing table can be restored by clone.

Proven reuse applies where the warehouse can confirm a table exists but has no trustworthy signal for when its data last moved. Models whose entire lineage is seeds and other models are still proven and skipped, which on most projects is the majority of the transformation layer. Anything fed by a source rebuilds, recorded as Cannot tell if source data changed rather than skipped on a guess. This is the deliberate choice: a warehouse without freshness metadata gets the savings it can prove and none of the risk it cannot.

Safe fallback applies everywhere else. The run executes exactly as it would have, and there is nothing to configure.

What You See on a Run

A run that reused anything carries a summary at the top of its output:

State-aware run: reused 14 of 22 nodes (3 cloned) - 8 executed

Every skipped model appears in the run results with an explicit reason rather than vanishing:

In the run resultsMeaning
NO-OP (DbDeux State: fingerprint unchanged)Proven identical to the last successful run
CLONE (DbDeux State: restored via zero-copy clone)Target was missing and was restored from an identical version elsewhere
A model absent from both listsRebuilt normally, with its reason recorded on the State tab
NO-OP (DbDeux State: test inputs unchanged)A test whose inputs were all proven unchanged

Post-run actions can key off this. A notification or a dashboard refresh set to fire on success with data changes stays quiet on a night where nothing actually changed, so an alert arriving means something.

State Analytics

Each environment has a State tab that turns reuse into numbers you can act on, over a 7, 30, or 90 day window:

What it showsWhat you do with it
Reuse by daySee reuse hold steady, or spot the day a change started forcing full rebuilds
Node outcomesThe split across reused, cloned, rebuilt, skipped by dbt, and errored
Reuse rate and estimated time savedA concrete figure for what the feature is returning to you
Top models by savingsWhich expensive models benefit most, and which never qualify
Why models rebuiltThe reason every rebuild happened, ranked by how many models it accounted for
By engineA native versus hosted comparison when you have used both

The Why models rebuilt table is the part teams end up using most. Reuse being lower than expected is a question with an answer: a volatile timestamp in a widely used macro, a source whose freshness cannot be read, or a job flag that disables reuse. Each of those is fixable once you can see it.

Reasons in Plain Language

Rebuild reasons are written as sentences, not codes, and each one carries an explanation on hover of what it means and what to do about it:

ReasonWhat it is telling you
Model changed since the last runIts SQL, its configuration, or something it builds on changed. The expected reason after a deploy
Depends on a model that had to rebuildFixing the upstream reason usually unlocks reuse for the whole chain
SQL produces different results each runSomething like a current timestamp or a random value means the output cannot be proven identical
Cannot tell if source data changedYour warehouse exposes no reliable freshness signal for that source, so the model is rebuilt rather than assumed
Table missing from the warehouseThe fingerprint matched but the target was gone, so it was rebuilt or restored
First run - no history yetThere was no baseline to compare against. Reuse starts on the next run
Run flags turned reuse offA full refresh or similar flag was in play, which always wins
Has pre/post hooksHooks can have effects outside the table, so the model always executes
Materialization always executesEphemeral and view-style materializations are not reuse candidates
Fast restore failed, rebuilt insteadA clone was attempted, did not succeed, and the normal build took over

Every reason is grouped and counted, so "why is our reuse rate 40 percent" resolves to one or two named causes instead of a hunt through logs.

Choose Your Engine

State-aware runs are enabled per environment, and you choose what powers them.

DbDeux State (native)dbt State (dbt Labs hosted)
Where the comparison happensInside your run, against your own warehouseA hosted service operated by dbt Labs in the US
What leaves your accountNothingMetadata: rendered SQL hashes and freshness timestamps. Never row data
Extra costNoneBilled by dbt Labs per daily active target table
SetupOne checkboxA dbt platform account with dbt State access, plus its credentials added to the environment
WarehousesFull reuse on Snowflake, BigQuery, and Databricks. Proven reuse on Redshift, PostgreSQL, MotherDuck, Microsoft Fabric, Azure Synapse, and Athena. Anything else runs normallySnowflake, Databricks, BigQuery, and Redshift
Restore a missing tableClone restore on Snowflake, BigQuery, and DatabricksNot available
Test reuseYesNo
Rebuild reasonsPer-model reason recorded for every rebuildNot reported

Native is the default, and for most teams it is the right answer: nothing to buy, nothing to sign, and no metadata about your project leaves your account. The hosted option exists because it covers more warehouses today, and because some teams have already bought it.

Switching engines is a radio button on the environment's state card. Analytics keep both engines' history separately, so you can compare them on your own project rather than taking anyone's word for it.

Turning It On

  1. Open the environment and find State-aware runs
  2. Tick Enable state-aware runs for this environment
  3. Leave the engine on DbDeux State (native), or pick the hosted engine and add its credentials on the Variables tab
  4. Let the next scheduled run finish

The first run after enabling has no baseline, so it builds everything and records the baseline. Reuse starts with the run after that. Numbers appear on the State tab once a scheduled job on this environment has succeeded.

Reuse comes from scheduled jobs on the environment. Editor runs and ad-hoc commands always execute normally, which is what you want while you are iterating.

How It Compares

Capabilitydbdeux state-aware runsOrdinary scheduled dbtdbt Cloud with dbt StateHand-rolled state comparison
Unchanged models skippedAutomatic, proven per modelNever, the project rebuilds every runYes, through a hosted serviceOnly as well as your script
Setup effortOne checkbox on the environmentNot applicableA hosted account, credentials, and per-table billingBuild and maintain artifact plumbing yourself
Where comparison data goesStays in your warehouse and your accountNot applicableMetadata sent to a hosted serviceWherever you store artifacts
Extra vendor costNoneNoneBilled per daily active target tableYour team's time
Source data changes detectedYes, from warehouse last-modified metadataNot applicableYesRarely, most scripts only compare code
Missing table recoveredRestored by clone where supportedFull rebuildFull rebuildFull rebuild
Warehouse coverage shown to youA per-warehouse tier on the State tab, so expectations are set before the first runNot applicableSupported list onlyWhatever you documented
Test reuseYesNoNoNo
Reason for every rebuildRecorded per model and aggregatedNot applicableNot reportedNot available
Failure modeFalls back to a normal full runNot applicableDepends on service availabilitySilent staleness if the comparison is wrong
Savings visibleReuse rate, estimated time saved, per-model breakdownNot applicableLimitedBuild your own reporting

The two properties worth holding onto: the comparison is conservative, so reuse never trades correctness for speed, and it is transparent, so you always know why a model rebuilt. A skip you cannot explain is a skip you cannot trust, which is why the reason taxonomy exists at all.