The one thing to understand first
In a rolling deployment, old and new application code run simultaneously for a window. If a migration changes the schema in a way only the new code understands, the old code breaks — and if you deploy code first, it references columns that do not yet exist. The expand/contract pattern (also called parallel change) makes every step backward-compatible so old and new code coexist safely.
Never let schema and code change in lockstep: add the new shape, run both shapes in parallel until all old code is gone, then remove the old shape — three deploys, not one. Every “safe migration” technique in this pathway is just a special case of this parallel-change discipline.
The three phases
- Expand. Add the new schema elements additively — new columns/tables alongside the old ones. Nothing is removed; old code is unaffected.
- Migrate. Make both shapes consistent: dual-write from the application (or via triggers), backfill historical data, and switch reads to the new shape once it is complete.
- Contract. After all code uses the new shape and you are confident, remove the old elements.
Each phase is deployed and verified independently. A rollback at any point is safe because earlier phases left the old shape intact.