Migrating without losing data
db-migrationPROdatabasemigrations
Changes a schema so both the old and new code survive it — and so does a rollback.
Was er tut
- Triggers on “add a column”, “rename this field”, “change the type”, “write a migration”.
- Starts from the fact that old and new code overlap in production for minutes, and on a rollback for much longer. Everything else follows.
- Splits a rename into four deploys: add, write to both, backfill, switch reads, drop later. A rename in one step breaks every running instance of the old code at once.
- Puts a drop in a later deploy than the code that stopped using it. Otherwise a rollback leaves code expecting a column that is gone.
- Asks the row count before, not after: a backfill over ten thousand rows is a statement, over ten million it is a batched job, or the lock takes the site down.
- Requires the down migration to be written and read, and if the data cannot come back, to say so in the file itself — so the person at 3am knows before running it.
- Verifies against a copy of production data: an empty database proves only that the syntax parsed.
Wozu er gut ist
Migrations do not break on syntax. They break because somebody forgot the five minutes when both versions of the code are live. Duplicates blocking a new unique constraint, nulls in a column about to be required, a lock on a large table — all of it is visible only on real data, and only if the question was asked in advance.
Wohin damit
- 1Legen Sie im Projekt den Ordner .claude/skills/db-migration an
- 2Legen Sie dort eine SKILL.md mit dem Text unten ab
- 3Fertig. Claude Code lädt den Skill selbst, sobald eine Aufgabe zur Beschreibung passt
Damit der Skill in allen Projekten statt nur in einem funktioniert, legen Sie ihn in ~/.claude/skills statt in den Projektordner.
SKILL.md-Datei
# Changing a schema while the app is running
The old code and the new code overlap in production for at least a few
minutes, and on a rollback for much longer. Every migration must leave
both able to run.
That single constraint decides almost everything below.
## The safe shapes
**Adding a column:** nullable, or with a default. A `NOT NULL` column
with no default fails the moment old code inserts a row.
**Renaming:** never in one step. Add the new column, write to both,
backfill, switch reads, stop writing the old one, drop it later. Four
deploys, not one. A rename in a single migration breaks every running
instance of the old code at once.
**Changing a type:** the same shape as a rename. Widening (int to
bigint, varchar to text) is usually safe in place; narrowing never is.
**Dropping anything:** in a separate, later deploy from the code thatDie Datei dieses Skills gehört zur PRO-Auswahl
Zugang freischalten