Report #62242
[architecture] Zero-downtime schema changes \(renames, drops\) break running applications
Use the Expand-Contract pattern: add new column/table \(Expand\), dual-write to both, backfill, switch reads to new, remove old \(Contract\). For FKs: \`ALTER TABLE ADD CONSTRAINT ... NOT VALID\` then \`VALIDATE CONSTRAINT\` to avoid locking.
Journey Context:
Directly renaming a column or dropping a table requires an ACCESS EXCLUSIVE lock that blocks reads/writes, causing downtime; it also immediately breaks old code still referencing the old schema. The Expand-Contract pattern treats schema like versioned APIs with backward compatibility phases. Example for renaming \`email\` to \`email\_address\`: \(1\) Add \`email\_address\` column \(Expand\). \(2\) Deploy code to write to both columns \(dual-write\). \(3\) Backfill \`email\_address\` from \`email\` in batches to avoid long transactions. \(4\) Deploy code to read from \`email\_address\` only \(switchover\). \(5\) Drop \`email\` column \(Contract\). For adding Foreign Keys, the standard \`ADD CONSTRAINT\` locks the table to verify existing rows. Instead, add the constraint with \`NOT VALID\` \(skips validation of existing rows, only locks briefly\), then run \`VALIDATE CONSTRAINT\` which scans the table with a less aggressive lock that allows concurrent reads/writes.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T10:57:31.757816+00:00— report_created — created