migration-safety-review
Skill0 starsChanged 4 months agoMITView on GitHub
Review a pending database migration for irreversible data loss and for locks that take the site down during deploy — dropped columns, narrowed types, NOT NULL without a default, and indexes built non-concurrently. Use before running any migration against a real database, or when reviewing a schema change.
- Deletes or force-pushes
In this repository19 other files it gives its agents.
- client-secret-sweepSkill
- codebase-onboarding-mapSkill
- commitSkill
- crawlability-auditSkill
- dependency-outage-auditSkill
- deploy-drift-checkSkill
- empty-state-auditSkill
- env-drift-checkSkill
- fake-data-guardSkill
- honest-metrics-auditSkill
- money-math-reviewSkill
- n-plus-one-finderSkill
- prompt-injection-reviewSkill
- pr-reviewerSkill
- release-notes-writerSkill
- retry-safety-reviewSkill
- route-auth-sweepSkill
- timezone-reviewSkill
- webhook-safety-reviewSkill
The file
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 9 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈9
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 39
Never review a migration from the ORM model diff alone.
- Distinctive: line 98
Add the new nullable column, write to both, read from the old.
- Distinctive: line 100
Read from the new.
- Distinctive: line 101
Only in a LATER deploy, drop the old.
- Distinctive: line 103
If a migration drops or tightens anything the current release still uses, say it must be split.
- Distinctive: line 152
No lock warning without a row count.
- Distinctive: line 153
Check compatibility with the CURRENTLY DEPLOYED code, not just the new code.
- Distinctive: line 154
When a migration is genuinely safe, say so in one line.
- Distinctive: line 160
Keep this line and others can find it too.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Migration Safety Review
Install
Save this file as ~/.claude/skills/migration-safety-review/SKILL.md, or
.claude/skills/migration-safety-review/SKILL.md to scope it to one repo. Claude
Code auto-discovers it. Invoke with /migration-safety-review or by asking "is
this migration safe to run?".
Why this exists
A migration is the one routine deploy step that can be unrecoverable. Application bugs get rolled back; a dropped column is gone unless someone happens to have a backup from before, and knows it, and can restore it under pressure.
Two independent risks, and reviews usually catch only the first:
- Data loss. Destructive and irreversible.
- Locks. Perfectly reversible schema changes that hold an exclusive lock long enough to stall every query, taking the site down for the length of the migration on a table large enough to matter.
The second is what turns a two-line change into an outage, and it never shows up in staging because staging has a thousand rows.
Step 1 — Read the actual SQL, not the intent
# Prisma
npx prisma migrate diff --from-schema-datasource prisma/schema.prisma --to-schema-datamodel prisma/schema.prisma --script
git diff -- '*migration*' '*schema*'Never review a migration from the ORM model diff alone. The generated SQL is what runs, and generators make destructive choices — a renamed field routinely becomes DROP plus ADD, which is a rename that deletes every value.
Step 2 — Classify every statement
IRREVERSIBLE (data is destroyed)
DROP TABLE,DROP COLUMNALTER COLUMN ... TYPEnarrowing: text→varchar(n), bigint→int, timestamp→dateDROP CONSTRAINTon a unique key that was deduplicating- Any
DELETE/UPDATEembedded in the migration
BLOCKING (site stalls while it runs)
ADD COLUMN ... NOT NULLwithout a default, on a non-trivial tableCREATE INDEXwithoutCONCURRENTLY(Postgres)ALTER COLUMN ... TYPErequiring a full table rewrite- Adding a foreign key without
NOT VALIDthen a separateVALIDATE
SAFE
ADD COLUMNnullable, or with a constant default on modern PostgresCREATE INDEX CONCURRENTLY- New tables
- Widening a type
Step 3 — Size the tables involved
Severity is entirely a function of row count, so get it rather than assume:
SELECT relname, n_live_tup FROM pg_stat_user_tables ORDER BY n_live_tup DESC LIMIT 20;A blocking operation on 500 rows is a non-event. The same operation on 5 million is an outage. Never report a lock risk without the row count next to it, or you will either cause panic or be ignored.
Step 4 — Check reversibility honestly
For each migration ask: if this is wrong, what is the recovery?
- Reversible in code — a down migration genuinely restores prior state.
- Reversible from backup only — then confirm a backup exists, is recent, and that someone has actually restored one before. An untested backup is a belief.
- Not reversible — the data is gone. This must be stated in the report in those words, not softened.
A down that recreates a dropped column restores the SCHEMA, never the VALUES.
Reviews routinely mark these reversible. They are not.
Step 5 — Check it is compatible with the running code
During a deploy, old and new application code run simultaneously. A migration that is safe in isolation breaks that window:
- Dropping a column the currently-deployed code still reads → errors until the deploy finishes.
- Adding
NOT NULLbefore the new code writes it → inserts from old code fail.
The fix is the expand/contract pattern, deliberately across two deploys:
- Add the new nullable column, write to both, read from the old.
- Backfill.
- Read from the new.
- Only in a LATER deploy, drop the old.
If a migration drops or tightens anything the current release still uses, say it must be split. That is the single most valuable output of this review.
Step 6 — Rewrite the dangerous ones
Offer the safe form concretely:
-- Unsafe: full table lock while the index builds
CREATE INDEX idx_orders_buyer ON orders(buyer_id);
-- Safe: no write lock (cannot run inside a transaction)
CREATE INDEX CONCURRENTLY idx_orders_buyer ON orders(buyer_id);
-- Unsafe: rewrites and fails on existing rows
ALTER TABLE users ADD COLUMN plan text NOT NULL;
-- Safe: three steps, no long lock
ALTER TABLE users ADD COLUMN plan text;
UPDATE users SET plan = 'free' WHERE plan IS NULL; -- batch on a big table
ALTER TABLE users ALTER COLUMN plan SET NOT NULL;Step 7 — Report
Migration: <name> Target: <db> Largest table touched: <n> rows
IRREVERSIBLE
<statement> -> destroys <what>, recovery: <backup only | none>
BLOCKING
<statement> -> locks <table> (<n> rows) for approximately <estimate>
safe form: <rewrite>
INCOMPATIBLE WITH RUNNING CODE
<statement> -> <file:line> still reads this; split into expand/contract
SAFE
<n> statements
VERDICT: safe to run | run in a maintenance window | must be split firstEnd with one verdict line. Someone is about to type a command and needs an answer, not a discussion.
Rules
- Review the generated SQL, never the model diff.
- A down migration restores schema, not data. Never call a drop reversible.
- No lock warning without a row count; severity is row count.
- Check compatibility with the CURRENTLY DEPLOYED code, not just the new code.
- When a migration is genuinely safe, say so in one line. Hedging every review trains people to skip them.
From Toolbay. Free to use, modify, and share. Keep this line and others can find it too.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

