Overview

Prisma Migrate turns schema changes into SQL files under prisma/migrations/ and records what has run in the _prisma_migrations table. migrate dev authors migrations locally; migrate deploy applies them in CI and production. Treat a migration as immutable once any environment has applied it. The general migration contract is in migrations.

Author with migrate dev and ship with migrate deploy

# Local: diff schema against migrations, write SQL, apply it
npx prisma migrate dev --name add_product_sku
 
# CI and production: apply pending migrations, no prompts
npx prisma migrate deploy
  • migrate dev uses a shadow database to compute the diff and may offer to reset your local database when history is inconsistent. Never run it against production.
  • migrate deploy applies migrations missing from _prisma_migrations, never creates new ones, and does not detect drift. Run it before the new application version takes traffic. migrate status reports whether history and database agree.
  • In Prisma 7, migrate dev and db push no longer run prisma generate or seed scripts. Add npx prisma generate to your workflow.
  • Commit the SQL with the schema change; reviewers read the SQL.

Configure the shadow and direct connections in prisma.config.ts

prisma.config.ts holds datasource.url and datasource.shadowDatabaseUrl; directUrl was removed in Prisma 7. The schema engine needs a direct, unpooled connection, so point datasource.url at the direct database URL when your application uses a pooler; see prisma-pooling. The shadow database needs permission to create and drop databases, or an explicit shadowDatabaseUrl.

Baseline an existing database

A database that already has a schema needs a baseline, or migrate deploy fails on tables that exist.

mkdir -p prisma/migrations/0_init
npx prisma migrate diff --from-empty --to-schema prisma/schema.prisma \
  --script > prisma/migrations/0_init/migration.sql
npx prisma migrate resolve --applied 0_init

Run the resolve step against every environment that already has the schema. A fresh environment runs migrate deploy and executes the baseline as normal SQL.

Detect drift with migrate diff

Drift means the database no longer matches what the migration history produces: a hand-run ALTER TABLE, a half-applied migration, or an edited shipped file.

npx prisma migrate diff \
  --from-migrations prisma/migrations \
  --to-config-datasource \
  --exit-code

Exit code 0 means no differences, 2 means differences, 1 means an error. In development, fix drift with prisma migrate reset. In production, write a corrective migration; do not edit shipped ones.

Edit generated SQL for what Prisma cannot express

Use prisma migrate dev --create-only to write the migration without applying it, then edit the SQL for custom indexes, triggers, backfills, or CREATE INDEX CONCURRENTLY on a hot table (postgres-indexes). Prisma has no documented flag to disable the migration transaction. Reports from Prisma’s issue tracker indicate that on Postgres a file with several statements runs as one implicit transaction, so keep CREATE INDEX CONCURRENTLY as the only statement in its own migration file and test it before relying on it.

Squash long histories with the documented steps

Long histories slow shadow-database replay and migrate reset. To squash:

  1. Delete the contents of prisma/migrations/.
  2. Create prisma/migrations/000000000000_squashed_migrations/migration.sql from migrate diff --from-empty --to-schema prisma/schema.prisma --script.
  3. Run npx prisma migrate resolve --applied 000000000000_squashed_migrations on every environment that already ran the old history.

Squashing drops custom SQL you added by hand to old migrations; re-add views, triggers, and similar objects afterwards. Squash only when every environment has applied everything.