safe-migrations
Safe Migrations
Every Rails developer ships a migration that locks the table for 90 seconds at some point. This skill prevents that. The rules are: never alter a column type, never change a column default on a large table in one step, never enforce NOT NULL on a backfill in the same migration, never index a 100M-row table without
CONCURRENTLY. AI agents botch every one of these by default.
Why this matters
A migration locks rows; an unsafe migration locks the whole table; a really unsafe migration locks the table for the duration of a pg_dump-sized table rewrite. Users see 502s. The fix isn't smarter Rails — it's deploy ordering and the strong_migrations gem.
The opinion
Install strong_migrations on day one. Treat every schema change as a multi-deploy split: add → backfill → enforce → cleanup. Use
CONCURRENTLYon Postgres for every index over ~10k rows. Backfill in batches of 1000 with throttling. Never trustchange_columnto be safe.
Counter-position: tiny apps (< 100k rows on all tables) can ignore this and just run migrations. We acknowledge that — but installing strong_migrations on day one means the first time you cross a threshold, you get a helpful error instead of an outage.
The mental model
A schema change is a contract between the schema and the deployed code. The code expects column X to exist (or not exist), to be NOT NULL (or nullable), to have a particular type. If the schema and the code disagree at any point during deploy, requests fail.
So every "big" schema change is at least two deploys: