Migrate in expand and contract, never in place
Splitting a schema change into an additive step, a migration period where both shapes are readable, and a removal step keeps every intermediate state rollback-safe, which an in-place change never is.
Do this firstDeploy dark; release with a flag
Add the new shape. Write both, read the old. Move readers. Stop writing the old. Remove it. Five deploys where an in-place change was one.
This is the control that decides whether the reversibility you bought elsewhere is real, because a database is the one part of the system that does not roll back with the binary. Teams routinely achieve a one-command rollback of code and then discover it is unusable, because the version they would roll back to cannot read the data the new version has been writing for six hours.
The decoy
A migration with a tested down-script. It is reversible in the test environment, where there is no traffic and no data written between the two runs. In production the down-script is a data-loss event with good intentions.
Evidence
- I Depended on You and You Broke Me: An Empirical Study of Manifesting Breaking Changes in Client Packages — II11.7% of client packages and 13.9% of their releases were hit by a manifesting breaking change during non-major dependency updates, and 44% of those arrived in minor and patch releases — the versions the contract says are safe. Clients recovered in only 39.1% of cases.
- Breaking Bad? Semantic Versioning and Impact of Breaking Changes in Maven Central — II83.4% of upgrades comply with semantic versioning, and compliance has increased over time. Critically for blast radius: "most BCs affect code that is not used by any client, and... only 7.9% of all clients are affected by BCs" — breaking changes are common in API surfaces and their realised reach is far smaller than raw counts suggest.
Last reviewed 2026-08-19.