Expand and Contract Database Migration Pattern
Expand and Contract evolves database schemas with zero downtime by adding new structures, migrating in phases, then removing the old ones. Each step is independently deployable and reversible, making schema change safe under live traffic.
Best Practice: Expand and Contract Database Migration Pattern
Expand and Contract, also called Parallel Change, is a pattern for evolving a database schema or interface without downtime and without breaking running code. Instead of changing a column or table in place, you first expand the schema to support both the old and new shapes, migrate clients and data across in controlled phases, then contract by removing the obsolete structures. Described by Martin Fowler and detailed in refactoring-databases work by Sadalage and Ambler, it lets teams deploy schema changes continuously and roll back safely at each step.
Step-by-Step Implementation Guidance
- Expand: add the new column, table, or structure alongside the existing one without removing anything.
- Write to both old and new structures so data stays consistent during the transition.
- Backfill existing rows into the new structure with an idempotent, batched job.
- Migrate reads to the new structure once it is fully populated and verified.
- Stop writing to the old structure after all clients read from the new one.
- Contract: remove the old column, table, or code path once nothing depends on it.
- Deploy each phase independently so any step can be paused or reversed.
Common Mistakes Teams Make When Ignoring This Practice
- Renaming or dropping columns in a single migration, breaking older application instances mid-deploy.
- Skipping the dual-write phase, so data diverges between old and new structures.
- Backfilling in one large transaction that locks tables and causes outages.
- Contracting too early, before every client has moved to the new structure.
- Not making backfill jobs idempotent, so re-runs corrupt or duplicate data.
Tools and Techniques That Support This Practice
- Migration tools: Flyway, Liquibase, Alembic, and Rails Active Record migrations.
- Online schema change: gh-ost and pt-online-schema-change for large MySQL tables.
- Feature flags: to switch read and write paths safely between phases.
- Batch jobs: background workers for incremental, idempotent backfills.
How This Practice Applies to Different Migration Types
- Cloud Migration: Apply the pattern when re-platforming data stores in the cloud so cutover happens without downtime.
- Database Migration: This is the core database-migration technique for evolving schemas under live traffic safely.
- SaaS Migration: Use phased expand-and-contract when reshaping data behind SaaS APIs to avoid breaking consumers.
- Codebase Migration: Coordinate code changes with each schema phase so old and new code both work during the transition.
Checklist
- New structures are added before old ones are touched.
- Writes target both old and new during transition.
- Backfill jobs are batched and idempotent.
- Reads move to the new structure only after backfill.
- Old structures are removed only when unused.
- Each phase deploys and rolls back independently.
During modernization and migration work, expand and contract database migration pattern is most valuable when it is treated as a continuous discipline rather than a one-time setup. Teams that codify the practice, measure its outcomes, and review it regularly keep risk low and feedback fast as systems evolve. Start small with one team or service, prove the value with concrete metrics such as lead time and change failure rate, and then expand the practice across the portfolio. Pair it with the related practices in this library so that build, test, release, and operational concerns reinforce one another. Documenting decisions and automating enforcement makes the practice durable as people and priorities change, which is exactly what large, multi-team migrations demand to stay safe and predictable over time.