Sources change. Your DDL must change without breaking everything downstream.
ALTER TABLE stg_orders ADD COLUMN IF NOT EXISTS coupon_code TEXT;
ALTER TABLE stg_orders ALTER COLUMN amount_cents TYPE NUMERIC USING amount_cents::numeric;
TRUNCATE stg_orders; -- fast full reload of staging
DROP TABLE IF EXISTS tmp_old_extract; -- temp cleanup
Rules
- Additive first: new nullable columns and new tables are safe. Renames, type narrows, and drops are breaking โ coordinate with dbt models and dashboards before applying.
IF EXISTS / IF NOT EXISTSeverywhere in migration scripts so they are re-runnable (pipelines retry; migrations must survive retries).- TRUNCATE (not DELETE) for staging reloads: instant, minimal WAL. Never
TRUNCATE a mart โ rebuild via
CREATE OR REPLACE/ swap pattern instead. - DROP is forever without backups: snapshot or rename-to-archive
(
ALTER TABLE t RENAME TO t_retired_2026_09) before dropping anything shared.