What you will be able to do
- Explain what sample mode does to refs and sources, and how it differs from an --empty dry run
- Write relative and static time specs for the --sample flag
- Configure event_time on upstream models and sources so they can be sampled
- Predict how sample mode treats Python models and seeds, and which commands accept it, and use .render() to exclude a ref from sampling
Key concept
Sample mode — A run or build in which dbt replaces every ref and source with a time-filtered version. Models are built from a recent or chosen slice of real data instead of the full history.
1.Why build on a slice of real data
The --sample flag saves development and CI time on large tables. A staging model over five years of events can take many minutes to build. Most of that time goes into reading history the developer doesn't need to check a new column or join. In sample mode, dbt filters what each model reads, so the model is built from a small but real subset of its inputs.
Sample mode goes one step past a [schema-only dry run with --empty](lesson:1.12). An empty run proves the SQL compiles and the DDL succeeds, but the resulting tables have zero rows, so there is nothing to inspect. A sampled run puts actual rows in your development schema. You can query the output and compare it with what you expect, which catches logic errors that an empty table would hide.
Sampling has a cost. Each input is cut down independently, so a fact table from the last three days may join to dimension rows that fall outside that window. Some joins will come back sparse or empty. A sampled build is good for validating logic quickly. It does not prove that the full build is correct.
Checkpoint 1 of 7· Check yourself
A developer needs to spot-check the values a refactored model produces, without paying for a full build. Which approach fits?
--empty produces zero-row tables, so there are no values to check. --sample adds a sampling of real data to the development schema, and it only supports time-based sampling, not percentages.
“takes the --empty flag's validation of semantic results a step further by including a sampling of data”Source: docs.getdbt.com
Checkpoint 2 of 7· Exam question
A model's YAML config is shown below. ```yaml models: - name: stg_orders config: materialized: view ``` The team runs `dbt run --select stg_orders --sample="3 days"` in a CI job, but the sample window has no effect and the model still processes the full source table. Which change to the config block fixes this?
Correct answer: B — Add an `event_time` key naming the timestamp column that dbt uses to apply the sample time window to this model.
- A. Materialization type does not control whether sampling applies; view versus table changes how the result is persisted, not whether the time filter is evaluated. The model would still run unsampled after this change.
- B. Sample mode needs a designated timestamp column to know which rows fall inside the requested window, and that column is declared through the event_time config. Without it, dbt has nothing to filter refs and sources against, so the sample argument is effectively ignored.
- C. Full-refresh controls whether a table is dropped and rebuilt from scratch; it has no bearing on whether the sample time filter gets applied to refs and sources. Combining the two flags does not fix a missing timestamp declaration.
- D. A unique_key is used by incremental strategies and snapshots to identify a row's identity, not to establish which timestamp column the sample window filters against. It would not restore sample filtering here.
Sources1
2.Relative and static time specs
Sampling is time-based only. The value you pass to --sample describes a time window, never a row count or a percentage. The window can take two forms. Pick the form based on what you are testing: recent behaviour, or a specific period in the past.
| Spec | What it filters | Example value |
|---|---|---|
| Relative | From the time the command runs, back by an integer and a granularity (Hours, Days, Months, Years) | "3 days" or "6 hours" |
| Static | Between a defined start and end, given as dates and/or timestamps | "{'start': '2024-07-01', 'end': '2024-07-08 18:00:00'}" |
A relative spec moves with the clock, which makes it the usual choice during daily development. For an even larger model, set the window in hours, such as "6 hours". A static spec pins the window. That matters when the interesting data is in the past, such as last July's peak week, or when two people need to build against the same slice and compare results. The static example below mixes a plain date for the start with a full timestamp for the end, which is allowed.
dbt run --select path/to/stg_customers --sample="3 days"dbt run --sample="{'start': '2024-07-01', 'end': '2024-07-08 18:00:00'}"Checkpoint 3 of 7· Fill the gap
Which granularity completes this relative spec for a very large model?
dbt run --select path/to/stg_customers --sample="6 ? "Relative specs take an integer plus Hours, Days, Months or Years. Weeks, row counts and percentages are not supported.
Source: docs.getdbt.comCheckpoint 4 of 7· Exam question
A data engineer needs to validate `fct_incidents` against a specific historical incident window rather than a rolling window: every event between 2024-07-01 00:00:00 and 2024-07-08 18:00:00. Which command samples exactly that fixed window?
Correct answer: A — `dbt run --select fct_incidents --sample="{'start': '2024-07-01', 'end': '2024-07-08 18:00:00'}"` filters to that literal date range regardless of when the command runs.
- A. This uses the static time spec form of the sample flag, which takes explicit start and end values and filters refs and sources to exactly that range no matter when the command is run. That matches the requirement for a fixed historical window rather than a moving one.
- B. A bare duration string like "7 days" is a relative spec: it counts backward from the current run time, so the window it produces shifts every time the command executes. It cannot reproduce a specific historical date range on demand.
- C. Vars are just key-value inputs a model's Jinja can read if it was written to expect them; the sample flag's parser does not consume vars at all, so this would leave the model completely unsampled.
- D. Like the other relative spec, "1 week" is measured back from execution time rather than fixed calendar dates, so it drifts with every run and does not target the specific July window requested.
Sources1
3.event_time tells dbt which column to filter
A time window is only useful if dbt knows which column holds the time. That column is set with the event_time config, and it is set on the upstream node: the model, seed, snapshot or source that is being read. The model you are building doesn't need it for its own inputs to be sampled. If stg_orders is the ref being filtered, stg_orders carries event_time.
Choose the column that records when the event happened, such as account_created_at or session_began_at. Avoid load timestamps like _fivetran_synced, which say when a row was ingested. The same config also drives [microbatch incremental models](lesson:1.14), so a well-chosen event_time serves both features. Sources are often the largest inputs, so they are where sampling saves the most.
sources:
- name: source_name
tables:
- name: table_name
config:
event_time: event_timestampCheckpoint 5 of 7· Check yourself
A source table has order_placed_at (when the customer ordered) and _fivetran_synced (when the row landed). Which should be its event_time for sampling?
event_time should be the actual timestamp of the event. Ingestion columns such as _fivetran_synced are listed as not recommended, and sources do accept the config.
“Set the event_time to the name of the field that represents the actual timestamp of the event (like account_created_at).”Source: docs.getdbt.com
4.Which commands and nodes are sampled
--sample is accepted by exactly two commands: dbt run and dbt build. That list is shorter than the one for --empty, which also works with snapshot and compile. Don't assume the two flags work in the same places.
Some node types behave differently inside a sampled run:
- Python models don't support the flag. dbt ignores it for them, so they read their full inputs.
- Seeds are still created normally, with every row loaded. They are filtered only when a downstream node refs them, and seeds accept the event_time config like models, snapshots and sources, so set it on the seed to name its timestamp column.
- A specific ref can be excluded from sampling by appending .render(), as in {{ ref('stg_customers').render() }}. Use this when a small lookup model must stay complete: sample the large fact inputs, render the small dimension in full, and the sampled facts still find their matching dimension rows.
Checkpoint 6 of 7· Match them up
Match each node or syntax to how it behaves during a run with --sample
Tap a term, then the definition that fits it.
Python models ignore --sample, seeds are sampled only where they are referenced, and .render() opts a ref out of sampling. Ordinary refs with event_time are filtered.
“Seeds will be created normally, but are sampled when referenced by downstream nodes.”Source: docs.getdbt.com
Checkpoint 7 of 7· Exam question
Which statements accurately describe how the `--sample` flag behaves once a run is invoked with it? (Select all that apply.)(Select 3)
Correct answers: B, C, D — The flag applies the same time-filtered window automatically to both `ref()` and `source()` calls in the model.; The flag extends `--empty` by running the model against a real sampled slice instead of validating against zero rows.; The flag is silently ignored when a model is written in Python, so that model still processes its full dataset.
- A. Sampling is not limited to sources; ref calls are filtered by the same time window as source calls, so this description understates what the flag touches.
- B. Both ref and source calls are filtered by the same sample window by default, which is exactly why a model that lacks an event_time config on an upstream node can break the filtering chain.
- C. Sample mode builds on the empty flag's dry-run concept but swaps in an actual, time-bounded slice of data, giving semantic validation that a zero-row run cannot provide.
- D. Python models are outside the flag's current scope, so invoking sample mode against one has no filtering effect and the model still runs against its complete dataset.
- E. The flag only changes what is queried at run time; it never edits or persists any change to the model's SQL file on disk.
- F. Seeds are loaded in full when they are built directly; only when a downstream node references a seed does that reference get filtered by the sample window.
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.event_time only needs to be configured on the model you are running with --sample.Why is that wrong?
Sampling filters the refs and sources that model reads, so each referenced node needs its own event_time naming its timestamp column.
Covered in event_time tells dbt which column to filter
2.--sample works with the same commands as --empty, including snapshot and compile.Why is that wrong?
--sample is available only for run and build.
Covered in Which commands and nodes are sampled
3.A Python model run with --sample reads only the sampled window of its inputs.Why is that wrong?
Python models don't support the flag. It is silently ignored, so they process their full inputs.
Covered in Which commands and nodes are sampled
4.--sample can take a row count or a percentage, such as 10% of the table.Why is that wrong?
Only time-based sampling is supported, either as a relative window or as a static start and end.
Covered in Relative and static time specs
Practise it for real
Build a staging model in your development schema from three days of sampled input data
1.Add event_time to the source table that stg_customers reads, in its sources YAML under config, pointing at the column recording when each row's event occurred.
Why: Sample mode filters refs and sources by the column named in event_time.
You should see: dbt parses the project without errors.
2.Run dbt run --select path/to/stg_customers --sample="3 days".
Why: A relative spec filters the inputs back three days from now.
You should see: stg_customers is built in your development schema, and the run is faster than a full build.
3.Check the result. If stg_customers selects the event_time column, query its minimum and maximum in the built table. Otherwise, compare the table's row count with the source's row count.
Why: This confirms the filter was applied to the input.
You should see: Selected event_time values fall within roughly the last three days, or the row count is clearly lower than the full source.
4.Rerun with a static spec, such as --sample="{'start': '2024-07-01', 'end': '2024-07-08 18:00:00'}".
Why: A fixed window lets you test a known historical period reproducibly.
You should see: The table now holds only rows from that window, if the source has data for it.
Stuck? Get a nudge
If the table still holds every row, check that event_time is set on the upstream source, not only on the model.
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.https://docs.getdbt.com/docs/build/sample-flagOfficial docs
“can help to reduce build times and warehouse spend by running dbt in sample mode”
↩︎ Why build on a slice of real data“there are cases where not all joins will be populated”
↩︎ Why build on a slice of real data“Relative time specs: Filters sampled data from the time the command is run back to a specified integer and granularity.”
↩︎ Relative and static time specs“Static time specs: Filters your data between a defined start and end period using date and/or timestamp.”
↩︎ Relative and static time specs“you need to set event_time for some_model to the field that will be used as the timestamp”
↩︎ event_time tells dbt which column to filter“The --sample flag is available for the run and build commands.”
↩︎ Which commands and nodes are sampled“To prevent a ref from being sampled, append .render() to it”
↩︎ Which commands and nodes are sampled“When used, sample mode generates filtered refs and sources.”
↩︎ Key concept“you need to set event_time for some_model to the field that will be used as the timestamp”
↩︎ Exam trap 1“The --sample flag is available for the run and build commands.”
↩︎ Exam trap 2“The --sample flag is not currently available for Python models. If the flag is used with a Python model, it will be ignored.”
↩︎ Exam trap 3“it only supports time-based sampling for now”
↩︎ Exam trap 4“takes the --empty flag's validation of semantic results a step further by including a sampling of data”
↩︎ Checkpoint“When used, sample mode generates filtered refs and sources.”
↩︎ Prediction“Seeds will be created normally, but are sampled when referenced by downstream nodes.”
↩︎ Checkpoint - 2.
“dbt uses event_time to understand when an event occurred.”
↩︎ event_time tells dbt which column to filter“Set the event_time to the name of the field that represents the actual timestamp of the event (like account_created_at).”
↩︎ Checkpoint - 3.https://docs.getdbt.com/docs/build/empty-flagOfficial docs
“The run, build, snapshot, and compile commands support the --empty flag.”
↩︎ Which commands and nodes are sampled