Data & DatabasesLesson 4 of 59 min

Migrations, or changing your mind safely

Code can be rolled back in seconds. Data cannot. Here is how people handle that.

Deploying new code is reversible: put the old version back. Changing your database is not, because the new version has been writing data in the new shape the whole time. This asymmetry is why database changes get more ceremony than anything else in a normal week.

A migration is a recorded, ordered, repeatable change to the shape of your data. Recorded so everyone applies the same changes; ordered so they apply in the same sequence; repeatable so your local machine, the preview environment, and production all end up identical.

The safe way to rename a column
  1. Add
    Create the new column. Nothing reads it yet. Fully reversible.
  2. Write both
    Deploy code writing to old and new. Both are correct.
  3. Backfill
    Copy historical values across. Still reversible.
  4. Read new
    Deploy code reading the new column. Old one is now dead weight.
  5. Drop
    Only now remove the old column, days later, once you are sure.

Five deploys to rename a column looks absurd until you notice what it buys: at no point do old code and new data coexist in a broken combination. During a deploy both versions are briefly running at once, and this sequence is the reason that is survivable.

What to remember

  • Code rolls back; data does not.
  • Migrations must be recorded, ordered, and repeatable across environments.
  • Expand, migrate, then contract. Never rename in one step.

Terms in this lesson

Field notes

Loaded from a deliberately slow source. The lesson above was already readable while this was still travelling. That is streaming, and it is the same trick a chat interface uses.

Fine at 500 rows, dead at 500,000

A list page loaded posts, then fetched each author separately. Development had eleven posts. The launch had four thousand, and every visitor issued four thousand queries. The database saturated eight minutes after the announcement.

The N+1 problem, at scale

The rename that took the site down

A column was renamed in a single migration during a deploy. For forty seconds the old code was still running and querying a column that no longer existed. Expand-then-contract exists precisely for those forty seconds.

Postmortem, e-commerce team

resolved in 900ms · region iad1

Hide field notes toggles a search param the loader reads. With it off, the slow promise is never created, so nothing streams.