An incremental model materializes as a table that is fully built on the first run, then on later runs processes only new or changed rows instead of rebuilding everything.
Flow
First run (or --full-refresh)
→ CREATE TABLE AS / full rebuild of the SELECT
Later runs
→ filter SELECT to new/changed rows (is_incremental)
→ append or merge into existing table ({{ this }})Minimal pattern
{{ config(
materialized='incremental',
unique_key='order_id'
) }}
select
order_id,
customer_id,
amount,
updated_at
from {{ ref('stg_orders') }}
{% if is_incremental() %}
where updated_at > (
select coalesce(max(updated_at), '1900-01-01') from {{ this }}
)
{% endif %}What dbt does conceptually
1. Compile SQL (with or without the incremental filter). 2. If table missing / full refresh → build full table. 3. Else apply the configured incremental strategy (merge, append, etc.) using the filtered query as the "new batch."
When to use
Large facts that grow daily; full table rebuilds become too slow or expensive.
Interview tip: Always state the grain, the watermark column, and the strategy. Incremental without a clear change key or watermark is a common production footgun.