What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Expand-and-contract is a staged way to change a live database schema while old and new application versions may overlap. Instead of making one breaking change, you add the new shape, migrate data and application behavior, then remove the old shape only after it is no longer used. That reduces compatibility risk; it does not guarantee that every schema operation is lock-free or that users will see no disruption.
Why use expand-and-contract?
A direct rename or removal can break an older application version that still expects the original column or table. During a rolling deployment, old and new instances can run at the same time. Expand-and-contract preserves compatibility across that overlap by keeping both schema shapes available until the transition is complete.
The approach is useful for renames, representation changes, and removals. A straightforward additive field that existing code does not need may not require the full sequence. The right implementation depends on the application architecture and database capabilities.
The three phases
Expand: add the new shape
Add the new field, table, or other structure without removing the old one. The expanded schema should still work with the old application. OpenStack Glance’s contributor guidance makes this requirement explicit: “Expand migrations MUST be additive in nature.” That is Glance’s project guidance, not a universal rulebook for every migration system. See the OpenStack Glance database migration guidance.
#1 Best Overall
Migrate: move data and behavior
Populate the new structure with existing data and update application behavior in stages. If writes can continue while historical rows are being backfilled, keep both representations in sync until the application has moved over. This can be done in application code, with database triggers, or through a migration tool’s supported mechanism. Choose an observable, repeatable process appropriate to the table and workload; there is no universal batch size or throttle.
OpenStack Glance separates data migration from schema changes in its phase model. Prisma’s example likewise keeps the old and new representations while adding a status enum, backfilling it from published, and updating the application. The number of releases and transaction behavior are specific to the workflow, not requirements shared by all tools. See Prisma’s expand-and-contract guide.
Contract: remove the old shape
After relevant code and other consumers have stopped using the old structure, remove it and any temporary synchronization mechanism. Do not treat the end of one application deployment as proof that every consumer has moved; scheduled jobs, reports, scripts, and prepared queries may also depend on the old shape.
Example: safely renaming a column
Suppose an application uses orders.status and the desired name is orders.order_status. Renaming the column immediately can break instances that still query status. A staged change looks like this:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsRank #3
- Check compatibility: inventory application versions and other consumers, and decide how writes will keep the two fields correct during the transition.
- Expand: add
order_statuswhile retainingstatus. Confirm the old application continues to work against the expanded schema. - Synchronize writes and backfill: ensure new or changed orders update the new representation, then populate historical rows. Make the backfill observable and safe to retry where appropriate.
- Move reads: deploy application code that reads
order_status. Validate that the new values meet the application’s correctness conditions and allow old application instances to finish their rollout. - Contract: once no relevant code or consumers use
status, remove it and retire temporary synchronization.
Dual writes are useful when writes continue during the backfill and the new field must stay current. They are not mandatory in every design: a database trigger or a migration tool’s supported mechanism may handle synchronization instead. Andrew Farries’s PostgreSQL example at PGDay UK 2025 follows the same general sequence: add a field, write both representations, backfill, shift reads, then drop the old field after the later application rollout. The presentation identifies pgroll as an open-source PostgreSQL tool; it is an example, not an independent evaluation. Watch the PGDay UK 2025 presentation.
Checks before each transition
Before expanding
- List application versions and non-application consumers that read or write the affected structure.
- Confirm the old application can operate with the expanded schema.
- Define how writes and historical data will remain consistent, and how you will detect incomplete or incorrect migration results.
During migration
- Track backfill progress and failures; make the process safe to retry if its design permits.
- Check the transformed data against application-specific correctness conditions before changing reads.
- Monitor operational effects such as workload impact and replication lag where relevant.
Before contracting
- Verify the new reads are deployed and the old application rollout has completed.
- Check that jobs, reports, scripts, and other consumers no longer depend on the old shape.
- Confirm the data checks have passed and decide how recovery would work if removal causes a problem.
What expand-and-contract does not guarantee
The pattern addresses compatibility between application releases and schema states. It does not make database DDL inherently nonblocking, prevent long-running work, eliminate replication lag, or protect against a faulty transformation or an overlooked consumer. Lock behavior and operational precautions depend on the database engine, its version, the operation, and the workload. For example, consult version-specific guidance such as Zero-Downtime Schema’s technical guide, then verify the exact operation against the engine and version you run rather than assuming its examples apply unchanged.
Whether a single breaking migration is acceptable depends on whether every application instance and consumer can be coordinated, whether data can be moved safely, the operational cost and duration of migration work, the database’s DDL behavior, and available rollback or recovery options. Expand-and-contract trades a single incompatible transition for several controlled steps; it does not remove the need to plan those steps.
Rollback gets harder after contract
Before the old structure is removed, rollback may be possible by restoring the previous application behavior, provided both representations remain valid. After contract deletes the old field or data, restoring old code may no longer be enough: recovery can require restoring data or applying a compensating migration. Decide what rollback means at each phase before starting, especially before destructive cleanup.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




