Create a file in the snapshots/ directory with a {% snapshot %} block; configure strategy (timestamp or check), unique_key, and for timestamp strategy specify the updated_at column.
For check strategy, list the columns to monitor in check_cols; dbt hashes those columns and inserts a new row when the hash changes, preserving the prior row with its dbt_valid_to set to the current timestamp.
Set target_schema to a dedicated schema (e.g., snapshots) so snapshot tables do not clutter the analytics layer.
Run dbt snapshot on a schedule (typically after each source refresh) to detect and record changes; the command is idempotent—running it when no rows changed produces no new snapshot rows.
Downstream models should query the snapshot table filtering WHERE dbt_valid_to IS NULL to get the current version of each entity, or join on a date range to get the historical version at a point in time.
Add a meta.owner and description to the snapshot YAML config for documentation and lineage tracking.
Known gotchas
If the source table is truncated and reloaded (rather than updated), dbt snapshot will see all rows as new inserts and will not detect deletes; use the invalidate_hard_deletes config option to mark missing source rows as expired.
timestamp strategy requires a reliable updated_at column; if the source system does not always update that column on every change, use check strategy instead.
Snapshot tables accumulate rows indefinitely; plan for long-term storage growth and consider archiving or partitioning old versions after a retention period.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp