Data & Analytics
A dbt incremental run replaces a production table with empty data
An unexpected initial-build path can turn an incremental model run into a table replacement. Protect row counts and rebuild authorization while retaining managed schema evolution.
October 25, 2026
An incremental job finishes, yet its production table is empty. A dbt Community question describes an unexpected initial-creation path during a delete+insert run. The post does not establish a dbt defect; it exposes a dangerous gap between the team’s assumed run mode and the actual target state.
Determine why the target was rebuilt
Preserve the job invocation, compiled SQL, adapter logs, relation type and target environment. Check whether the relation existed where dbt expected it, whether --full-refresh was supplied, and whether materialization or naming changed. dbt’s incremental-model guide explains when is_incremental() is true and why the model SQL must also work on an initial build.
Separate schema changes from destructive rebuilds
Use on_schema_change deliberately for compatible column evolution, then test its limits. It does not backfill old rows when new columns appear. dbt also supports a resource-level full_refresh: false setting to override a full-refresh flag, but that alone cannot protect a missing or renamed target relation.
Add a production invariant
Before promotion, compare expected target identity, minimum row count and key coverage. If a replacement is intentional, require an explicit release step and a recoverable backup or time-travel path supported by the warehouse. For routine runs, fail the deployment if an existing high-value table would be replaced or emptied unexpectedly.
Adovo’s view
An incremental label is not a data-preservation guarantee. The guarantee comes from knowing which relation will be touched, how it can be rebuilt, and what evidence must pass before consumers see it.
