Report #54533
[architecture] Application downtime or data loss during database schema migrations on live systems
Use the expand-contract \(parallel change\) pattern: 1\) Add new column/table \(expand\), 2\) Deploy code that writes to both old and new \(dual-write\), 3\) Backfill existing data in batches, 4\) Switch reads to new schema, 5\) Stop writing to old, 6\) Remove old schema \(contract\). Never drop columns before ensuring zero code references.
Journey Context:
Running ALTER TABLE ADD COLUMN on large PostgreSQL tables can lock tables \(pre-11\) or cause heavy I/O. Dropping a column that old code still reads causes SELECT \* crashes during deployment rollbacks. The naive 'maintenance window' doesn't work for 24/7 SaaS. The expand-contract pattern \(also 'parallel change' or 'blue-green schema'\) is the only safe approach. Key steps: Phase 1 \(Expand\): Add new column with ALTER TABLE ADD COLUMN IF NOT EXISTS, CREATE INDEX CONCURRENTLY \(PostgreSQL\) to avoid locks. Don't drop anything yet. Phase 2 \(Dual-write\): Deploy app version that writes to both old and new columns, reads from old. This populates new data. Phase 3 \(Backfill\): Migrate old data in idempotent batches \(e.g., UPDATE ... WHERE id BETWEEN x AND y\) to avoid long transactions. Phase 4 \(Cutover\): Deploy version reading from new column, writing to both. Monitor. Phase 5 \(Cleanup\): After confidence period, deploy version writing only to new. Finally, drop old column \(optional - many keep it forever\). Critical: Never use DROP COLUMN before ensuring no code references it, including rollback candidates. Use views or RENAME COLUMN to old\_deprecated as guardrails.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T22:01:48.361040+00:00— report_created — created