---
topic: databases
author: Crashtech Editorial
published: Nov 13, 2026 · read: 4 min
---

A Safer Database Rename Takes Three Deployments

Expand-and-contract migrations keep old and new application versions compatible while a schema changes, but they require observability and a rollback plan.

– –

A bridge cannot close one lane because a new lane is planned. The work crew builds beside the traffic, moves vehicles in stages, checks the load, and only then removes the old span. A live database change has the same constraint: old and new application processes may be running at the same time.

That is why a one-line column rename can become a production incident during a rolling deploy. One application instance expects surname; the new version expects family_name; a background worker may lag behind both. Expand-and-contract gives those versions a period of compatibility.

Expand before switching

The expand phase adds the new column or table without removing the old one. New code must still work against the old schema if that is part of the deployment sequence, and old code must continue working after the new structure appears. PostgreSQL documents that ALTER TABLE operations vary in their effects and locking behavior; even a quick metadata operation can wait behind other transactions. The database version and exact operation matter. PostgreSQL documentation

A safe rollout commonly looks like this:

  1. Add the new nullable field or compatible structure.
  2. Deploy code that writes both old and new fields, or uses a compatibility layer.
  3. Backfill existing rows in bounded batches, watching load and replication lag.
  4. Verify that values match and that new code can read from the new structure.
  5. Switch reads to the new structure and observe errors and data quality.
  6. Stop writing the old structure, then remove it in a later deployment.

Martin Fowler describes this general pattern as Parallel Change: introduce a new interface, migrate callers, and remove the old interface only after the transition. It is useful beyond databases because the compatibility problem also appears in APIs and message formats. Parallel Change

Backfills are production workloads

A backfill that updates every row in one transaction can hold locks, create a large write burst, fill logs or compete with normal traffic. Treat it like a workload with a rate limit. Process a bounded range, make progress resumable, and record the last completed position. Re-running a batch should not corrupt already-migrated rows.

Monitor the signals that reveal harm: lock waits, transaction duration, database load, replication lag, error rate and the count of rows still missing the new value. A migration that “finished” because its script exited is not proven correct until the data invariant is checked.

Compatibility is the real rollback plan

During the transition, a rollback may mean returning application code to a version that still expects the old field. If the new code wrote only the new value, rolling back could expose missing data. Dual writes preserve options, but they create a consistency obligation: both values must be updated together or reconciled.

Before rollout, write down which application versions can coexist with each schema state and what to do if a stage fails. Some destructive changes cannot be rolled back safely after data is removed. In those cases, a forward fix or restore may be the only path; calling a migration “reversible” does not make deleted data reappear.

For a concrete large-scale example, see the Atlassian database migration coverage. A migration story is most useful when it distinguishes the data-copy mechanics from the compatibility contract that application code must preserve.

When the extra stages are worth it

For a small internal table with a maintenance window, a direct migration may be simpler and safer. Expand-and-contract adds temporary code, storage and monitoring work. It is most valuable when old and new instances overlap, downtime is costly, or the migration affects widely used data.

The key question is not “Can the DDL run?” It is “Can every version that may be alive during this rollout understand the schema it will see?” Stage the transition around that answer, and make the final cleanup a separate decision after the new path is proven.

A bridge crew adds a parallel lane while traffic continues over the original bridge.
Conceptual illustration of staged schema change; it does not depict a real construction project.
Advertisement

Frequently asked questions

What is an expand-and-contract migration?

It is a staged schema change that first adds a compatible representation, then moves application reads and writes to it while the old representation remains available, and finally removes the old structure after all deployed code and data no longer depend on it. The stages let mixed application versions coexist during a rollout.

Why not rename a database column in one deployment?

A single rename can break old application instances that still query the previous name during a rolling deployment, and it can make rollback difficult. A staged migration keeps both forms available until every running process, background job and external consumer has moved, though the extra period of dual support must be monitored.

Does expand-and-contract guarantee a zero-downtime migration?

No. Locks, backfills, replication lag, long transactions, application bugs and data inconsistency can still cause an outage. The approach improves compatibility but must be paired with database-specific lock analysis, bounded backfills, metrics, rehearsal and a tested rollback or forward-fix plan.

Sources & further reading

/* Comments */