MervCodes

Tech Reviews From A Programmer

How to Fix Prisma Migration Errors

1 min read

Prisma's migration system is one of the best parts of the ORM, but it can also be one of the most frustrating when things go wrong. A failed migration in development is an annoyance; a failed migration in production can take down your application. This guide walks through the most common Prisma migration errors, why they happen, and exactly how to fix them.

Understanding How Prisma Migrations Work

Before fixing errors, it helps to understand what Prisma is actually doing. When you run prisma migrate dev, Prisma compares your schema.prisma file against the current state of your database, generates a SQL migration file, applies it, and records the result in a special table called _prisma_migrations.

That _prisma_migrations table is the source of truth. It stores a checksum of each migration and whether it succeeded. Most "mysterious" Prisma errors come from a mismatch between three things: your schema file, the actual database structure, and the migration history recorded in that table. Once you internalize that, debugging becomes much more systematic.

Error: "Drift detected: Your database schema is not in sync"

This is the single most common error developers hit. Prisma is telling you that the live database no longer matches what the migration history says it should be. This usually happens because someone changed the database manually, restored a backup, or applied a migration outside of Prisma.

In development, the fastest fix is to reset:

npx prisma migrate reset

This drops the database, recreates it, and replays every migration from scratch. Never run this against production — it deletes all data.

If you can't lose data, inspect the drift first:

npx prisma migrate diff \
  --from-schema-datasource prisma/schema.prisma \
  --to-schema-datamodel prisma/schema.prisma \
  --script

This prints the SQL needed to reconcile the difference, which you can review and apply deliberately.

Error: "Migration failed to apply cleanly to the shadow database"

Prisma uses a temporary "shadow database" during migrate dev to verify migrations are valid. If your migration contains SQL that the shadow database rejects, you'll see this error.

Common causes include:

  • Insufficient permissions. The database user needs permission to create and drop databases. On hosted providers, create a dedicated shadow database and point to it with shadowDatabaseUrl in your datasource block.
  • Raw SQL referencing objects that don't exist yet in the migration sequence.
  • Extensions not installed, such as uuid-ossp or postgis.

To configure a manual shadow database:

datasource db {
  provider          = "postgresql"
  url               = env("DATABASE_URL")
  shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
}

Error: "The migration was modified after it was applied"

Prisma stores a checksum for every applied migration. If you edit a migration file after it has already run, the checksum no longer matches and Prisma refuses to continue.

The rule is simple: never edit an applied migration. Instead, create a new migration that makes the additional change. If you genuinely need to fix a migration that hasn't been deployed anywhere except your local machine, reset and regenerate it.

If the migration was only applied locally and you understand the risk, you can mark it as re-applied:

npx prisma migrate resolve --rolled-back <migration_name>

Error: A Migration Is Stuck in a Failed State

In production, you might see that a migration started but never finished — often because of a transient error, a timeout, or a constraint violation against existing data. Prisma will block all further migrations until you tell it how to handle the failed one.

You have two options. If you manually completed the migration's intent (or the partial changes are fine), mark it as applied:

npx prisma migrate resolve --applied <migration_name>

If you reverted the partial changes and want Prisma to forget it, mark it rolled back:

npx prisma migrate resolve --rolled-back <migration_name>

Then run npx prisma migrate deploy again to continue.

Error: Data Loss Warnings on Schema Changes

When you rename a column or change a type, Prisma sometimes can't tell the difference between a rename and a "drop old column, add new column." It warns you about potential data loss and may refuse to proceed non-interactively.

The fix is to write the migration by hand. Generate the migration without applying it:

npx prisma migrate dev --create-only

Then open the generated SQL file and replace the destructive DROP/ADD statements with a proper ALTER TABLE ... RENAME COLUMN. Apply it afterward with npx prisma migrate dev. The --create-only flag is your best friend for any non-trivial schema change.

Error: "Environment variable not found: DATABASE_URL"

This one is mundane but extremely common. Prisma CLI commands don't automatically load your .env file in every context. Make sure your .env is in the project root, or load it explicitly:

npx dotenv -e .env.production -- npx prisma migrate deploy

In CI/CD pipelines, confirm the environment variable is actually injected into the step running the migration — a surprising number of "broken migrations" are just missing secrets.

Best Practices to Avoid Migration Errors

Prevention beats cure. A few habits eliminate most migration pain:

  • Use migrate dev only in development and migrate deploy in production. Never run migrate dev against a production database — it can prompt for destructive resets.
  • Commit migration files to version control. They are part of your codebase, not generated artifacts to ignore.
  • Review generated SQL before applying, especially for renames, type changes, and added constraints.
  • Use --create-only for risky changes so you can edit the SQL by hand.
  • Run migrations in CI against a copy of production to catch failures before they reach real users.
  • Back up production before deploying migrations. A 30-second snapshot saves hours of recovery.
  • Keep one source of truth. Don't mix manual database edits with Prisma migrations.

A Reliable Recovery Workflow

When a migration breaks in production and you're under pressure, follow a calm sequence rather than guessing:

  1. Read the exact error message and identify the migration name involved.
  2. Check the _prisma_migrations table to see which migration is marked as failed or unfinished.
  3. Decide whether the partial changes should be kept or reverted.
  4. Use prisma migrate resolve to set the correct state.
  5. Re-run prisma migrate deploy.
  6. Verify the schema with prisma db pull or prisma migrate status.

The npx prisma migrate status command is invaluable here — it tells you exactly which migrations are applied, pending, or failed without changing anything.

Frequently Asked Questions

Can I delete the _prisma_migrations table to start over? Only in development. Deleting it in production divorces Prisma from your real schema state and almost always causes worse problems. Use migrate reset locally instead.

What's the difference between migrate dev and migrate deploy? migrate dev is interactive — it creates new migrations, runs the shadow database check, and may prompt for resets. migrate deploy is non-interactive and only applies already-existing migrations. Use deploy in production and CI.

How do I undo the last migration? Prisma has no built-in "down" migration. To roll back, write a new migration that reverses the change, or restore from a backup. This is why reviewing migrations before applying matters so much.

Why does migrate dev keep trying to reset my database? It detects drift between the migration history and the actual database. Something changed the database outside of Prisma. Identify the manual change, or accept the reset in development.

Do I need a shadow database in production? No. The shadow database is only used by migrate dev. Production deployments use migrate deploy, which doesn't need one.

Is it safe to edit a migration file? Only if it has never been applied anywhere. Once a migration runs, editing it breaks the checksum and corrupts history. Make a new migration instead.

Migration errors feel scary, but nearly all of them trace back to a mismatch between your schema, your database, and Prisma's recorded history. Once you can read that triangle, the fix is usually a single deliberate command — not a panic-driven reset.

Sources

Related Articles