The key takeaway

Separate adding a schema, moving data and removing old structures into distinct steps. Keep overlapping application versions compatible, make backfills resumable, and define recovery before changing production data. Rolling back application code does not automatically reverse a database migration.

Map readers and writers first

List every consumer of the field or table: web requests, background jobs, exports and administrative scripts. A migration is incomplete if the main application changes while a nightly integration still writes the old format.

Write down which application versions will coexist and what each expects. The compatibility window must cover delayed workers and long-running jobs as well as the normal deployment duration.

Expand before you remove

For a column rename, one possible sequence is to add the new column, deploy compatible writes, backfill existing rows, switch reads and finally remove the old column. Each step should leave a usable application behind.

Dual writes require care. If both values live in the same database, update them within the same transaction where appropriate. If multiple systems are involved, define reconciliation rather than assuming both writes always succeed.

Treat backfills as production workloads

A backfill competes with customer traffic. Process bounded batches, record a checkpoint and make repeated batches safe. Measure progress alongside database load and request latency so you can pause when the application is affected.

DecisionQuestion to answer before execution
Batch sizeHow much work can run without disrupting normal traffic?
CheckpointWhere will the next run resume after interruption?
ValidationHow will missing or mismatched records be detected?
CancellationCan the job stop safely between batches?

Avoid assuming a schema operation is cheap because it changes little SQL. Locking and rewrite behavior depend on the database, operation and table size. Rehearse against a representative dataset and inspect the execution behavior for your environment.

Define recovery at every stage

Before switching readers, compare the old and new representations. Keep the old structure long enough to investigate discrepancies. Mark the step after which reverting application code is no longer a sufficient recovery plan.

A destructive migration may require a forward repair or a restore. Decide which is feasible before deleting data, and verify the restore procedure separately from deployment rollback.

Ship the cleanup deliberately

Schedule removal as a tracked follow-up with an owner. Confirm that old application versions and jobs have drained before dropping compatibility code. Include these gates in your CI/CD release process, alongside the database workload decisions that shaped the migration.

All insightsDiscuss your project