When would you make a dbt model incremental instead of a view or full table rebuild, and how do you keep an incremental model correct when data arrives late or the logic changes?
technical-conceptual · Mid level · data-ml
What the interviewer is really asking
Tests practical dbt judgment: choosing incremental materialization as a cost optimisation only when full rebuilds get too slow, using is_incremental with a lookback window and a unique_key, and knowing every incremental model needs a documented full-refresh path for logic changes and accumulated drift.
What to say
- Frame incremental as a performance optimisation, not a default: start with a view, move to a table when querying it is slow, and only go incremental when rebuilding the full table each run is too slow or expensive. Incremental processes just the new/changed rows since the last run, trading build cost for added complexity.
- Get the incremental logic right: wrap the filter in is_incremental() so the first run builds everything and later runs only process recent rows (filtering on an event/updated timestamp), and set a unique_key with a merge or delete+insert strategy so re-processed rows update in place rather than duplicate.
- Handle late data and logic changes explicitly: add a lookback window (re-scan the last few hours/days, not just strictly-new rows) so late-arriving events get picked up, and document a full-refresh path — every incremental model needs one for when you change the transformation logic or discover the incremental runs have drifted (duplicates, missed rows).
What to avoid
- Reaching for incremental materialization by default for performance, before confirming a table or view is actually too slow — adding complexity you don't need yet.
- Filtering strictly on rows newer than the current max timestamp with no lookback, so any late-arriving event is silently missed forever.
- Having no full-refresh strategy, so when the model logic changes the historical rows keep their old (now wrong) values and the table quietly drifts.
Example answers
Strong: A fact model took 40 minutes to rebuild nightly and was mostly recomputing unchanged history. I made it incremental with is_incremental() filtering on event_ts and a unique_key with the merge strategy, which cut the build to 3 minutes — and I added a 3-day lookback window because our events sometimes landed two days late, so those weren't dropped.
Weak: I make every model incremental from the start because it's the fastest to run.