The Compatibility Contract
during any deploy window, TWO code versions hit ONE schema:
[v1 pods]──┐
├──►[schema S'] ← who breaks?
[v2 pods]──┘
BACKWARD-COMPATIBLE migration rules keep both alive:
SCHEMA changes that are safe mid-roll:
✓ ADD nullable column / column with default
✓ ADD new table/index (CONCURRENTLY!)
✓ WIDEN constraints gradually (NOT NULL only after backfill)
SCHEMA changes that break a neighbor:
✗ DROP/RENAME columns v1 reads
✗ ADD NOT NULL without default (v1 inserts fail!)
✗ TIGHTEN check constraints against existing patterns
✗ CHANGE column types/meanings
the mental model: every migration must leave the schema
serving the PREVIOUS release perfectly.
The Multi-Release Pattern
breaking changes decompose across RELEASE boundaries:
GOAL: rename users.phone → phone_number
RELEASE N: add phone_number nullable; app writes BOTH
RELEASE N+1: backfill; app READS new column only
RELEASE N+2: stop writing old column
RELEASE N+3: drop old column (census confirmed zero readers)
each release deploys independently and safely;
rollback at ANY point stays functional because
every intermediate state served two versions.
this is expand-contract STRETCHED across releases —
slower but bulletproof for high-stakes tables.
Enforcement, Not Vibes
compatibility violations slip through review constantly.
mechanical checks:
□ CI LINTERS on migrations: forbid DROP/RENAME/NOT-NULL-
without-default in normal migrations (require explicit
escape-hatch flags + review)
□ CONTRACT TEST matrix: previous-release app version ×
new schema — run in CI against migrated staging clone
□ COLUMN-LEVEL USAGE tracking: which services SELECT/INSERT
which columns (audit logs / query analysis) → safe-drop census
□ DEPLOY TOOLS aware of DB state: block deploys when
pending incompatible migration pairs detected
culture line for reviews:
"what does the PREVIOUS version experience during this
migration's entire window?" — unanswerable = not ready.
| Violation | Production symptom |
|---|---|
| dropped column early | v1 pods error-burst mid-roll |
| NOT NULL added pre-backfill | inserts fail on old instances |
| renamed field in API+schema same day | mobile clients break for weeks |
| index added blocking | write stall during “simple” deploy |
Interview Framing
“How do you ensure rolling deploys never break on schema changes?” scored shape: the two-versions-one-schema framing first, safe/unsafe change lists, multi-release decomposition walked through one concrete rename, CI enforcement mechanisms named (linters+contract-matrix). This question tests whether your team treats compatibility as an ENFORCED CONTRACT or reviewer folklore — mechanics beat intentions.
Premium Content
Unlock Backward-Compatible Migrations and all premium lessons with a subscription.
All premium lessons
Ad-free experience
Priority support
From ₹199.99/year — See plans