pattern

Expand-Contract Migration

Changing a schema in additive steps that keep old and new code both working, so deployment and migration never have to be simultaneous.

The pattern has three phases separated by deployments. Expand: add the new column, table or index, leave the old one in place, and have the application write to both while still reading from the old. Migrate: backfill, and switch reads to the new shape. Contract: once no code path references the old shape and no rollback target does either, drop it.

The property this preserves is that at every moment, both the previous and the current version of the application work against the current schema. That is what makes rolling deployments and rollbacks safe, and it is why the pattern is a precondition for continuous delivery against a relational store rather than an optimisation of it.

The step teams get wrong is contract. Dropping the old column in the same release that stops writing to it removes the rollback target, and the drop is the one irreversible operation in the sequence. Contract belongs a release later — often several — and needs evidence that nothing reads it, which usually means logging reads before removing them.