Report #73447
[architecture] How to run database migrations without locking tables and causing downtime
Use the 'expand and contract' pattern: never rename or drop columns; instead, add new columns/tables in step 1, dual-write in step 2, backfill in batches in step 3, then switch reads in step 4, and finally deprecate old schema after release stability.
Journey Context:
Running 'ALTER TABLE' to add a default value or rename a column often acquires an ACCESS EXCLUSIVE lock in PostgreSQL, blocking all reads and writes until the rewrite completes \(potentially hours for large tables\). The common mistake is doing this in a single deployment. The expand-contract pattern treats schema changes like API versioning: you never modify in place. For example, to rename 'email' to 'email\_address', you add 'email\_address', write to both, backfill, then switch the app to read from new column, then drop old one in a later release. This requires application code to handle both schemas temporarily, but ensures zero downtime and rollback capability.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T05:52:28.155726+00:00— report_created — created