On this page
  1. Why do you need migrations?
  2. How do migrations work?
  3. How do migrations break deploys?
  4. Where AI coding assistants get this wrong
  5. Checklist
  6. FAQ
    1. What happens if I edit a migration that already ran?
    2. Should migrations run automatically on deploy?
  7. Related topics
  8. Sources
concept

What Are Database Migrations (and Why Do They Break Deploys)?

A migration is a versioned change to your database schema, applied in order. Learn how they work and the failure modes that take down deploys.

Quick answer

  • A migration is a versioned, ordered change to your database schema — adding a column, creating a table — applied once and tracked.
  • Migrations let schema changes deploy with code instead of being applied by hand in production.
  • The classic failure: a migration that runs on deploy and fails (or locks the table) brings the release down with it.

Why do you need migrations?

Without them, schema changes are applied by hand — someone runs ALTER TABLE in production, the change isn’t recorded, and the next developer’s local database is out of sync with prod. Migrations solve this by making schema changes code: a numbered, versioned list of changes that runs in order against any database and records which have applied. The same sequence takes a fresh database from zero to the current schema, which is how every environment stays identical.

How do migrations work?

A migration tool (Alembic for SQLAlchemy, Prisma Migrate, Django’s built-in migrations) tracks an applied-versions table in the database. Each migration is a file with an up() and down() step. Running migrate applies pending migrations in order; the tool records each one. Deploys run migrations before starting the new code, so the schema and the code arrive together. The down() step allows rollback — though rolling back a destructive migration (a dropped column) can’t restore the data, so down() often just documents the loss.

# Alembic: generate a migration from your model changes, then apply it\nalembic revision --autogenerate -m "add status column"\nalembic upgrade head\n# Verify applied versions:\nalembic current

How do migrations break deploys?

Four common ways. A migration that fails midway stops the deploy — which is why migrations run before the app starts. A long-running migration (adding a column with a default to a big table) locks the table and blocks traffic during the deploy. A migration that requires new code while old code is still running (add a NOT NULL column before the code writes it) errors on old instances. And destructive migrations (dropping a table) can’t be un-run. The mitigations: keep migrations small, test them against a copy of real data, and prefer additive changes that old code tolerates.

Where this bites vibecoders

The AI assistant adds a column to the model, and the app breaks in production because nobody ran the migration — or the assistant’s ‘just run ALTER TABLE in the dashboard’ advice creates a prod database that differs from every other environment. Migrations are the discipline that makes schema changes boring and repeatable, and asking the assistant to ‘generate the migration for this model change’ gets the versioned file into your deploy pipeline where it belongs.

Where AI coding assistants get this wrong

  • Modifying the model and never generating the migration, so prod schema drifts from code.
  • Writing migrations that add NOT NULL columns to tables with existing rows, failing on real data.
  • Autogenerating migrations from a local database that differs from prod, producing wrong diffs.
  • Destroying data in down() (dropping columns/tables) without warning or backup.

Checklist

  • Run migrations as part of the deploy, before the app starts.
  • Test migrations against a copy of production-sized data, not just an empty local DB.
  • Prefer additive changes (nullable columns, new tables) that old code tolerates.
  • Keep migrations small and reviewable; one logical change per migration.

FAQ

What happens if I edit a migration that already ran?

The migration tool records it as applied, so your edit never re-runs — and other environments that applied the original version now differ from you. Treat applied migrations as immutable: fix forward with a new migration instead of editing the old one.

Should migrations run automatically on deploy?

Yes, for most apps: the deploy runs migrate then starts the new code. The exception is schema changes that lock big tables or need manual review — those get a manual step in the runbook, applied with a maintenance window.

Sources

Share: