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.
How a Model Earns a Skip
A model is only skipped when dbdeux can prove nothing about it would change. Each run:
- Compiles the project, so every model's final SQL is known, not guessed from the file text
- 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
- Compares that fingerprint against the baseline from this environment's last successful state-aware run
- Confirms the model's table or view still exists in the warehouse
- 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.
| Warehouse | How the restore happens |
|---|---|
| Snowflake | Zero-copy clone. A metadata operation, so it is effectively instant and costs no compute |
| Google BigQuery | Zero-copy table clone, with the same properties |
| Databricks | Deep 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.
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 results | Meaning |
|---|---|
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 lists | Rebuilt 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 shows | What you do with it |
|---|---|
| Reuse by day | See reuse hold steady, or spot the day a change started forcing full rebuilds |
| Node outcomes | The split across reused, cloned, rebuilt, skipped by dbt, and errored |
| Reuse rate and estimated time saved | A concrete figure for what the feature is returning to you |
| Top models by savings | Which expensive models benefit most, and which never qualify |
| Why models rebuilt | The reason every rebuild happened, ranked by how many models it accounted for |
| By engine | A 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:
| Reason | What it is telling you |
|---|---|
| Model changed since the last run | Its SQL, its configuration, or something it builds on changed. The expected reason after a deploy |
| Depends on a model that had to rebuild | Fixing the upstream reason usually unlocks reuse for the whole chain |
| SQL produces different results each run | Something like a current timestamp or a random value means the output cannot be proven identical |
| Cannot tell if source data changed | Your warehouse exposes no reliable freshness signal for that source, so the model is rebuilt rather than assumed |
| Table missing from the warehouse | The fingerprint matched but the target was gone, so it was rebuilt or restored |
| First run - no history yet | There was no baseline to compare against. Reuse starts on the next run |
| Run flags turned reuse off | A full refresh or similar flag was in play, which always wins |
| Has pre/post hooks | Hooks can have effects outside the table, so the model always executes |
| Materialization always executes | Ephemeral and view-style materializations are not reuse candidates |
| Fast restore failed, rebuilt instead | A 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 happens | Inside your run, against your own warehouse | A hosted service operated by dbt Labs in the US |
| What leaves your account | Nothing | Metadata: rendered SQL hashes and freshness timestamps. Never row data |
| Extra cost | None | Billed by dbt Labs per daily active target table |
| Setup | One checkbox | A dbt platform account with dbt State access, plus its credentials added to the environment |
| Warehouses | Full reuse on Snowflake, BigQuery, and Databricks. Proven reuse on Redshift, PostgreSQL, MotherDuck, Microsoft Fabric, Azure Synapse, and Athena. Anything else runs normally | Snowflake, Databricks, BigQuery, and Redshift |
| Restore a missing table | Clone restore on Snowflake, BigQuery, and Databricks | Not available |
| Test reuse | Yes | No |
| Rebuild reasons | Per-model reason recorded for every rebuild | Not 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
- Open the environment and find State-aware runs
- Tick Enable state-aware runs for this environment
- Leave the engine on DbDeux State (native), or pick the hosted engine and add its credentials on the Variables tab
- 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
| Capability | dbdeux state-aware runs | Ordinary scheduled dbt | dbt Cloud with dbt State | Hand-rolled state comparison |
|---|---|---|---|---|
| Unchanged models skipped | Automatic, proven per model | Never, the project rebuilds every run | Yes, through a hosted service | Only as well as your script |
| Setup effort | One checkbox on the environment | Not applicable | A hosted account, credentials, and per-table billing | Build and maintain artifact plumbing yourself |
| Where comparison data goes | Stays in your warehouse and your account | Not applicable | Metadata sent to a hosted service | Wherever you store artifacts |
| Extra vendor cost | None | None | Billed per daily active target table | Your team's time |
| Source data changes detected | Yes, from warehouse last-modified metadata | Not applicable | Yes | Rarely, most scripts only compare code |
| Missing table recovered | Restored by clone where supported | Full rebuild | Full rebuild | Full rebuild |
| Warehouse coverage shown to you | A per-warehouse tier on the State tab, so expectations are set before the first run | Not applicable | Supported list only | Whatever you documented |
| Test reuse | Yes | No | No | No |
| Reason for every rebuild | Recorded per model and aggregated | Not applicable | Not reported | Not available |
| Failure mode | Falls back to a normal full run | Not applicable | Depends on service availability | Silent staleness if the comparison is wrong |
| Savings visible | Reuse rate, estimated time saved, per-model breakdown | Not applicable | Limited | Build 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.
Related
- Environments - where state-aware runs are enabled
- Job Scheduling - the scheduled runs that reuse applies to
- Multi-Warehouse Support - warehouse coverage