Development & Code · master area
Schema Migration
Four rules: backward-compatible, staged, tested in staging, reversible by default. A migration that breaks one rule is not a migration — it is an outage scheduled in advance.
Owners: Developer, Tech Lead Phase it lives in: How We Build (Volume IV) The corpus principle this enacts: Rollback possible is not. A confirmed time is.
Where it lives in the chain
- How We Build · Migration discipline — the canon: four rules
- How We Build · The Release · runbooks — where migration rollback is rehearsed
How to do this
The four rules, every migration:
- Backward-compatible — the migration runs against running code. The old code must still work after the migration runs. Adding a column is fine; renaming one is not — split it into add + dual-write + backfill + cutover + drop.
- Staged — runs in
dev→staging→production, with a soak window in each. The JWT outage shipped because staged-deploy was skipped. - Tested in staging — the migration is executed against staging data and verified. Not dry-run. Not "should be fine."
- Reversible by default — every migration has a tested down. A migration whose
downwas never run is a migration that cannot be rolled back.
What good practice looks like
The PR contains: the up, the down, the test that runs both, and the soak time named in the description. The down is run in CI against a fresh database state — if up then down doesn't produce the original schema, the build fails. The migration file references the story (GR-204_add_grading_shortcut_event.sql) so the postmortem trail is intact.
A migration that can't be reversed is a one-way door. Some are necessary — but they are named as one-way doors in the ADR, planned for, and reviewed at the change advisory board, not done casually.
Related crafts
- Migration Design — the upstream artefact
- Rollback Discipline
- Contract Testing — guards the API while the schema migrates