Handbook

The Postgres Migration Safety Handbook

A reference for the schema changes that take production down. Every entry names the lock a statement takes, cites the manual for it, and ends with a lab you can run against a throwaway PostgreSQL in under two minutes.

It is framework-neutral — Rails, Django, Alembic, Flyway, Liquibase, Prisma, Ecto, sqlx or hand-written .sql makes no difference to what PostgreSQL locks. It is written by the people who build MigrationPilot, but it is not a product manual: each entry ends with a note on which rule catches the problem, and you can skip that section and still get everything else.

20
entries
39
dated public incidents
17/20
graded High
2026-08-11
last verified

Locks, and the queue behind them

The mechanism underneath most migration outages: one statement waits, and everything arriving after it waits too.

Constraints without the outage

NOT NULL, CHECK, foreign keys and UNIQUE all default to a full scan under a lock. All four have the same two-step fix.

Rewrites you did not ask for

The ALTERs that quietly copy the whole table and every index on it — and the one that stopped in PostgreSQL 11.

Statements your framework will break

Migration tools wrap everything in a transaction by default. These three statements have opinions about that.

Changes you cannot take back

DROP and RENAME finish instantly, which is exactly why they get waved through review.

Past the edge of one table

Replication, backfills and partitions: migrations whose cost lands somewhere other than the table you named.

The evidence standard

Most writing about unsafe migrations is a chain of blog posts citing blog posts. Behaviour changes between major versions; the posts do not. These are the rules every entry here is held to.

  1. 1Version claims are pinned to release notes.

    Not "recent versions of Postgres".

  2. 2Lock claims are pinned to the manual.

    Not to another blog post.

  3. 3Every entry has a lab you can run.

    Real Docker, real output, under two minutes.

  4. 4Incidents are real, dated, and fetched.

    Or the entry says none was found.

  5. 5Confidence is graded, not implied.

    High or Medium. There is no Low.

Where no public postmortem could be found, the entry says so rather than inventing a plausible story. No incident here is composited or inferred. The markdown behind these pages lives in docs/handbook, and node docs/handbook/validate.mjs checks every entry against the standard above.