Report #7828
[architecture] Performing zero-downtime database schema changes without locking tables or breaking running code
Use the Expand-Contract pattern: 1\) Deploy a 'expand' migration that adds new columns/tables but keeps old ones \(backward compatible\), 2\) Update code to write to both old and new \(dual-write\), backfill data, 3\) Switch reads to new schema, 4\) Deploy 'contract' migration removing old columns.
Journey Context:
Directly altering large tables \(ADD COLUMN with DEFAULT, DROP COLUMN\) acquires ACCESS EXCLUSIVE locks on PostgreSQL, blocking reads/writes for seconds to minutes during which the application appears down. Simple 'create new table, copy data, rename' approaches require application downtime for the atomic rename. The Expand-Contract pattern \(also called Parallel Change or Blue/Green schema evolution\) treats schema changes like API versioning - never break backward compatibility during transition. Phase 1 \(Expand\): Add new column as nullable or with default, new tables, triggers to sync if needed - application old code still works. Phase 2 \(Migrate\): Deploy new code writing to both schemas \(dual-write\), backfill existing data in batches to avoid lock escalation. Phase 3 \(Switch\): Cutover reads to new schema \(feature flag\), verify. Phase 4 \(Contract\): Remove old columns/triggers once confident. Tools like gh-ost \(MySQL\) or pg-online-schema-change automate the mechanics, but the pattern applies universally. Critical trap: forgetting that DDL transactions in PostgreSQL can deadlock with application queries during the expand phase - run migrations in low-traffic windows or use ALTER TABLE ... CONCURRENTLY if supported.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T03:47:28.806732+00:00— report_created — created