How snapshots work
SQLBuild adds two generated columns to the target table:| Column | Meaning |
|---|---|
valid_from | When this version became valid (inclusive) |
valid_to | When this version stopped being valid (exclusive). NULL means currently active. |
valid_from <= point_in_time < valid_to.
Change detection strategies
Timestamp strategy
Use when your source has a reliable column recording when the entity changed.updated_at is newer than the active target row’s updated_at, SQLBuild closes the old version and inserts the new one. If updated_at is unchanged or older, nothing happens.
Check strategy
Use when the source does not have a reliable update timestamp.check_columns between source and active target rows. If any checked value differs, a new version is created. Changes to unchecked columns are ignored.
check_columns [*] checks all output columns except unique_key and the generated validity columns. Explicit columns are recommended for important models to avoid noisy history from volatile metadata columns.
Historical input
By default, SQLBuild treats the model query as returning the current state of each entity (one row perunique_key). When your source contains historical observations over time, add observed_at to switch to historical mode.
Historical check snapshot
Use for daily full exports or periodic snapshots without a business update timestamp.observed_at group is treated as a complete picture of the source at that time. Consecutive unchanged observations are collapsed into a single version.
Historical timestamp snapshot
Use for historical observations that include a business update timestamp.extract_date, the source’s current state for this key had this updated_at.” Validity windows use updated_at, not observed_at.
Historical change records
Use for CDC tables, audit logs, or historical backfills where rows are individual version records.updated_at determines version ordering. observed_at is arrival/load time, not validity time.
Historical input rules
| Strategy | historical_input | Source shape | Uniqueness | Hard deletes |
|---|---|---|---|---|
check | snapshot (default) | Complete observations over time | unique_key + observed_at | Allowed |
timestamp | snapshot | Complete observations with update timestamp | unique_key + observed_at | Allowed |
timestamp | changes | Individual change/version records | unique_key + updated_at | Not allowed |
check | changes | Not supported | - | - |
observed_at require historical_input to be set explicitly.
Hard deletes
- Current-state input: closed at execution time
- Historical input (
historical_input snapshot): closed at theobserved_attime of the group where the key is missing
historical_input changes because change-record batches are not complete source snapshots - a missing key just means no change, not deletion.
Reappearing keys create a new active version.
Configuration reference
| Field | Required | Description |
|---|---|---|
materialized snapshot | Yes | Enables snapshot lifecycle |
unique_key | Yes | Column(s) identifying one entity |
snapshot_strategy | Yes | timestamp or check |
updated_at | Timestamp only | Source column with business update time |
check_columns | Check only | Columns compared to detect changes. Use [*] for all non-key columns. |
observed_at | No | Source column with observation/extract time. Presence enables historical mode. |
historical_input | Conditional | snapshot or changes. Required for timestamp with observed_at. Defaults to snapshot for check with observed_at. |
invalidate_hard_deletes | No | Close active rows missing from source. Default false. |
valid_from_column | No | Override generated column name. Default valid_from. |
valid_to_column | No | Override generated column name. Default valid_to. |
initial_valid_from | No | First-version start time: updated_at, observed_at, or execution_time. See defaults below. |
snapshot_full_refresh | No | Model-level full-refresh safety: deny, require_confirmation, or allow. |
Initial valid_from defaults
| Case | Default |
|---|---|
Timestamp, no observed_at | updated_at |
Timestamp, with observed_at | updated_at |
Check, no observed_at | execution_time |
Check, with observed_at | observed_at |
Full refresh safety
Snapshot full refresh can permanently discard history that cannot be reconstructed from the source. SQLBuild guards against this with configurable safety policies.Project config
| Policy | Behavior |
|---|---|
deny | Full refresh is blocked regardless of CLI flags |
require_confirmation | Requires --allow-snapshot-full-refresh flag or interactive confirmation |
allow | No snapshot-specific confirmation required |
Defaults
| Snapshot type | Default policy | Reason |
|---|---|---|
Current-state (no observed_at) | deny | Cannot reconstruct older history from current-state source |
Historical (with observed_at) | require_confirmation | Can reconstruct if query returns full history, but SQLBuild cannot prove that |
Model override
The modelsnapshot_full_refresh field can only make the policy stricter than the project setting. A model cannot weaken deny to allow.
CLI usage
Audits
Snapshot models support the same audit system as other materializations. Audits withdelta_and_final run scope execute against the snapshot delta relation before target mutation, blocking promotion if an error-severity audit fails. Final audits run after target mutation.
Duplicate handling
SQLBuild fails with an actionable error if the source query produces duplicate rows at the snapshot identity grain:- Current-state: duplicate
unique_key - Historical snapshot: duplicate
unique_key + observed_at - Historical changes: duplicate
unique_key + updated_at

