Database migrations
29 free, verified agents, skills & packs for Claude Code - install with 'npx vanara install <name>'. Apache-2.0. From the Vanara catalog (206 items).
npx -y skills add vanara-agents/skills --skill database-migrationsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 22 days oldThe repository was created 22 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
How to write safe, reversible, zero-downtime database schema migrations — additive-first changes, the expand/migrate/contract pattern, batched backfills, concurrent index builds, safe NOT NULL, rollbacks, and the locking pitfalls that cause outages. A deep reference with runnable checks.
SKILL.md
7.7 KB, as published. Nobody here has run it
Database Migrations
A migration runs against live data while old code may still be serving traffic. The dangerous moment
is never the steady state before or after — it's the in-between, when the schema has changed but not every
app instance has. Design every change to be correct during that window. Heavy detail lives in
references/; copy-paste material in examples/; a runnable safety check in scripts/.
Mental model
Two things deploy on different clocks: your schema (one atomic change) and your code (rolled out instance-by-instance over minutes). A migration is safe only if both the old and new code work against both the old and new schema for the overlap window. That single rule explains almost every practice below.
| Concern | Safe answer |
|---|---|
| What changed | the smallest possible step |
| When old code sees it | it must still work (backward-compatible) |
| Locks held | none long enough to block traffic |
| If it goes wrong | a tested, reversible path back |
| Big rename/retype | expand → migrate → contract, across deploys |
1. Additive-first
Prefer additive, backward-compatible changes. Adding a nullable column, adding a table, or adding an
index never breaks code that doesn't know about it. Destructive changes (drop/rename column, change type,
add NOT NULL) break the old code still running mid-deploy, so they must be sequenced — see §3.
-- SAFE: old code ignores the new column; new code can start using it.
ALTER TABLE users ADD COLUMN email_verified_at timestamptz NULL;
-- UNSAFE in one step: old code still INSERTs rows without this column.
ALTER TABLE users ADD COLUMN email_verified_at timestamptz NOT NULL;
2. Never hold a long lock
Most outages from migrations are lock waits, not data loss. A statement that rewrites a table or takes
an ACCESS EXCLUSIVE lock blocks every read/write behind it, and that queue backs up into your connection
pool within seconds.
- Add columns as nullable (or with a constant default — on modern Postgres a constant default is metadata-only and does not rewrite the table; a volatile default does).
- Build indexes with
CREATE INDEX CONCURRENTLY(no table rewrite, no write lock — but it can't run inside a transaction). - Backfill in batches with short transactions, not one giant
UPDATEthat locks every row. - Set a
lock_timeoutso a migration that can't get its lock fails fast instead of stalling traffic.
SET lock_timeout = '3s'; -- fail fast rather than queue behind traffic
CREATE INDEX CONCURRENTLY idx_orders_status ON orders (status);
Full catalogue of which operations rewrite/lock and the safe alternative: references/zero-downtime-changes.md.
3. Expand / migrate / contract
The core pattern for any breaking change (rename, retype, split, add NOT NULL) without downtime. It
spreads one logical change across multiple deploys so old and new code always overlap safely:
- Expand — add the new shape (nullable column / new table / new index). Backward-compatible.
- Migrate — deploy code that dual-writes old+new, then backfill existing rows in batches, then switch reads to the new shape and verify.
- Contract — once nothing reads or writes the old shape, drop it in a later deploy.
Each step is independently deployable and independently reversible. The full worked walkthrough
(including a column rename and a non-null-ification) is in references/expand-contract.md.
4. Reversibility & safety
Every migration should declare how to undo it. Some operations are irreversible in practice
(DROP COLUMN, DROP TABLE, TRUNCATE destroy data; a down-migration can recreate the structure but
not the data). Treat those specially:
- Provide a real
downfor reversible ops; for irreversible ones, document that recovery is restore from backup, and take a verified backup/snapshot immediately before. - Separate the destructive
contractstep into its own migration so you can ship the safe parts and pause. - Dry-run on a production-like copy and time it — a 30-minute backfill on staging may be hours in prod.
Reversible-vs-irreversible rules, backup checklists, and dry-run guidance: references/rollback-and-safety.md.
Validate a .sql file with scripts/check-migration-reversible.mjs before shipping.
5. Operational discipline
- One concern per migration. Mixing a schema change and a data backfill in one file makes rollback ambiguous and the transaction huge.
- Forward-only in production. Prefer rolling forward with a fix over rolling back a migration that
already ran against live data; keep
downfor local/staging and emergencies. - Idempotent where possible (
IF NOT EXISTS,IF EXISTS) so a retried run after a partial failure doesn't error. - Backfills run outside the schema transaction, in batches with a sleep, so they don't hold locks or bloat WAL/replication lag.
Common pitfalls (failure modes)
NOT NULLin one shot — adds a column the still-running old code inserts NULLs into, or triggers a full validating scan. Add nullable, backfill, thenSET NOT NULL(validate via aCHECK ... NOT VALIDthenVALIDATE). See the zero-downtime reference.- Plain
CREATE INDEXon a hot table — takes a write lock for the whole build. UseCONCURRENTLY. - One giant
UPDATEbackfill — locks millions of rows, blocks writes, balloons WAL. Batch it. - Rename a column in one deploy — old code references the old name and 500s during the rollout window. Use expand/contract.
- Volatile/changing default on add-column — forces a full table rewrite under an exclusive lock.
- No
lock_timeout— the migration silently queues behind a long transaction and takes the app down. - Destructive
downthat "reverses" a drop — it recreates an empty column; the data is gone. Mark it irreversible and rely on backups.
When NOT to use / trade-offs
- Tiny project, maintenance window available. If you can take 5 minutes of downtime at 3am and the
table is small, a single blocking
ALTERis simpler and cheaper than a three-deploy expand/contract. Zero-downtime machinery is overhead you only need at scale or with strict SLAs. - Throwaway / pre-launch schemas with no real data — just recreate the schema; migrations add ceremony you don't need yet.
- NoSQL / schemaless stores shift the work to the application (versioned documents, read-time migration) rather than DDL — the expand/contract idea still applies, the SQL specifics don't.
- Data migrations vs schema migrations are different beasts; heavy data reshaping often belongs in a background job, not a migration runner that blocks deploys.
Files in this package
references/expand-contract.md— the expand/migrate/contract pattern, worked end-to-endreferences/zero-downtime-changes.md— per-operation safe recipes (add column, backfill, index, NOT NULL)references/rollback-and-safety.md— reversible vs irreversible ops, backups, dry-runsexamples/add-column-safe.sql— a safe, batched, reversible migrationexamples/migration-config.example.json— a migration runner config with safety guardrailsscripts/check-migration-reversible.mjs— Node check that flags irreversible SQL + missing down-migrations
Pairs with the database-scaling skill, the data-modeling skill, and the database-reviewer agent.