Report #87139
[architecture] How do I rename a column, split a field, or tighten a constraint without locking the table or breaking rolling deploys?
Use the expand-contract \(parallel change\) pattern in three reversible phases: \(1\) Expand — add the new column/table/index alongside the old without dropping anything; \(2\) Migrate — deploy code that dual-writes and batch-backfills existing rows; \(3\) Contract — switch reads to the new path, verify no code references the old structure, then drop it. Never rename-in-place or drop a column before all running code versions are done with it.
Journey Context:
During a rolling deploy, old and new application versions run against the same database simultaneously, so any breaking schema change must leave every intermediate state valid for both versions. A naïve \`ALTER TABLE ... RENAME COLUMN\` or \`DROP COLUMN\` acquires an exclusive lock and breaks in-flight requests. Expand-contract converts one risky change into several backward-compatible steps, each independently reversible. In PostgreSQL, add indexes with \`CREATE INDEX CONCURRENTLY\` and add nullable columns first, then backfill, then add \`NOT NULL\`. For very large tables under continuous write load, complement this with online schema-change tools like gh-ost or pt-online-schema-change.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T04:51:17.927933+00:00— report_created — created