dbt snapshot Command: Capturing State Changes Correctly
The dbt snapshot command is what actually executes the snapshot definitions covered in dbt Snapshots โ comparing the current state of a source against the last captured version, and recording any changes as new history rather than overwriting. Getting the operational details of running this command right matters more than it might seem, because a missed or mistimed snapshot run means permanently lost history that canโt be reconstructed after the fact.
Running Snapshots
dbt snapshotThis executes every {% snapshot %} block defined in the snapshots/ directory. Each one compares its source queryโs current output against the existing snapshot table and inserts new rows for anything that changed, based on whichever strategy (timestamp or check) that snapshot is configured with.
Running with dbt=1.8.0Found 2 snapshots
1 of 2 START snapshot snapshots.customers_snapshot ..... [RUN]1 of 2 OK snapshotted snapshots.customers_snapshot ...... [INSERT 0 ROWS in 1.4s]2 of 2 START snapshot snapshots.subscriptions_snapshot .. [RUN]2 of 2 OK snapshotted snapshots.subscriptions_snapshot ... [INSERT 14 ROWS in 0.9s]INSERT 0 ROWS for the first snapshot means nothing changed since the last run โ expected and normal for most runs of most snapshots most of the time. INSERT 14 ROWS means 14 rows had changes captured as new historical versions.
Selecting Specific Snapshots
dbt snapshot --select customers_snapshotUseful when different snapshots have genuinely different required cadences โ a snapshot of a rapidly-changing table might need to run hourly, while a slowly-changing one is fine running once daily, and running them on separate schedules means selecting them independently rather than always running the full set.
Scheduling Snapshots: Why Frequency Is a Real Decision, Not a Detail
Unlike dbt run, which is generally safe to re-run as often as you like, dbt snapshotโs frequency directly determines the granularity of history youโre able to reconstruct later. If a row changes twice between two scheduled snapshot runs, only the second change survives in the historical record โ the first is lost permanently, with no way to retroactively recover it.
# A typical production pipeline sequencedbt snapshotdbt rundbt testThis ordering โ snapshot before run โ matters when downstream models reference the snapshotโs current state; running snapshot first ensures the freshest possible historical capture is available before the rest of the pipeline builds on top of it.
What Happens If You Forget to Run Snapshots for a While
If a scheduled snapshot job silently fails for a week and nobody notices, any changes to the source data during that window are permanently unrecoverable in the snapshotโs history โ the source table has already moved on, overwriting whatever intermediate states existed. This is the strongest argument for actively monitoring snapshot job success, not just assuming a cron job that ran once will keep running correctly.
# A simple monitoring pattern: fail loudly, don't fail silentlydbt snapshot || (echo "SNAPSHOT FAILED - HISTORY GAP RISK" && exit 1)Debugging a Snapshot Thatโs Not Capturing Expected Changes
The most common cause: the updated_at column used by a timestamp strategy isnโt actually changing reliably when the underlying data changes.
-- Check whether updated_at is actually moving when data changesselect customer_id, region, updated_atfrom raw_app_data.customerswhere customer_id = 42order by updated_at descIf updated_at looks stale relative to a known data change, switching that snapshot to a check strategy against the specific columns you care about is usually the fix, as covered in dbt Snapshots.
Snapshot Target Schema Considerations
Snapshots default to building into whatever schema is configured, but itโs worth deliberately isolating them from regular model output, since snapshot tables grow indefinitely (theyโre append-only by design) and have a very different access/retention profile than regular transformation tables.
snapshots: my_project: +target_schema: snapshotsRunning Snapshots in CI
Snapshots are typically not run as part of CI validation for pull requests โ CI environments usually build against a temporary or sampled dataset, and running a snapshot there would pollute production history with test data, or fail entirely if the CI database doesnโt have the production snapshot tableโs existing history to compare against. Snapshots are almost always restricted to scheduled production runs only.
# Example: snapshot excluded from CI job, included in production scheduleci_job: commands: ["dbt build --exclude resource_type:snapshot"]production_job: commands: ["dbt snapshot", "dbt build"]Common Mistakes
Running snapshots against a CI or ephemeral database. This either fails (no prior history to compare against) or, worse, silently succeeds while writing meaningless test data into what should be a production historical record.
Not monitoring snapshot job success. A silently failing scheduled snapshot job means permanently lost history for that time window โ thereโs no way to retroactively recover it once the source data has moved on.
Choosing too infrequent a schedule for data that changes rapidly. If meaningful history is needed at finer granularity than the schedule provides, that history simply doesnโt exist and canโt be added retroactively.
Summary
| Behavior | Detail |
|---|---|
dbt snapshot | Compares current source state against captured history, inserts changes |
| Frequency | Directly determines historical granularity โ missed runs mean permanently lost history |
| CI exclusion | Snapshots should almost always be excluded from CI/PR validation runs |
| Monitoring | A failed snapshot job should alert loudly, not fail silently |
dbt snapshot is one of the few dbt commands where getting the operational cadence wrong has a genuinely irreversible consequence โ treat its scheduling and monitoring with more care than a typical model build.