Skip to main content
Prisma Documentation Docs

Search documentation

Type to search this documentation.

On this pageOverview

Rollbacks and recovery

People use "rollback" for two different problems, and Prisma ORM deals with them differently, so work out which one you have. If the migration applied but the change it made was wrong, you want a rollback, which in Prisma ORM is one more migration. If the migration failed partway, you want recovery instead: find the cause, fix it, and run the migration again, which is safe to do.

Prisma ORM has no migrate down command and no "down migration" files, because undoing a change is not a special kind of operation here. To undo a change you add a new migration to your migration history that changes the database back to an earlier state, and it is planned and applied like every other migration. If you know git, this is git revert rather than git reset: you add something that undoes the change instead of deleting it from history.

A rollback is a new migration, not rewritten historyStep 1 of 3

add_display_name applies cleanly and the database sits at the new state. Then the team decides the change was wrong.

Suppose you applied 20260707T1008_add_display_name in production and now need to undo it. Undoing it means planning a migration with npx prisma migration plan, which writes the difference between the two contract states you name. A contract state is one version of your contract, the contract.prisma file that replaced schema.prisma, named by its hash. You name a state with the migration directories you already have: a directory name means the state after that migration, and ^ after the name means the state before it. To undo add_display_name, then, you plan from its own state back to the state before it:

bunx prisma migration plan \

  --from 20260707T1008_add_display_name \

  --to "20260707T1008_add_display_name^" \

  --name rollback_display_name
Bash
pnpm prisma migration plan \
  --from 20260707T1008_add_display_name \
  --to "20260707T1008_add_display_name^" \
  --name rollback_display_name
Bash
yarn prisma migration plan \
  --from 20260707T1008_add_display_name \
  --to "20260707T1008_add_display_name^" \
  --name rollback_display_name
Bash
npx prisma migration plan \
  --from 20260707T1008_add_display_name \
  --to "20260707T1008_add_display_name^" \
  --name rollback_display_name
text
✔ Planned 1 operation(s)

migrations/app/20260707T1010_rollback_display_name
└─ ⚠ Drop column "displayName" from "user"

⚠ This migration contains destructive operations that may cause data loss.

from:       866ab885a8a4bd8d9f5adc47784c068be7895a7182c55cc29f9f9967d3019484
to:         967cb9f63587c1d90f64716780f04eec22b263424e89f07139233fc2c3d710c4
app space:  migrations/app/20260707T1010_rollback_display_name

ℹ DDL preview

ALTER TABLE "public"."user" DROP COLUMN "displayName";

Read the migration before you apply it, because db migrate runs destructive operations without asking you to confirm, and this one drops a column. Open its migration.ts, and run npx prisma migration show 20260707T1010_rollback_display_name to see its SQL. When you are happy with it, complete the rollback in this order:

  1. Save the data, if you need it. Dropping the column deletes what was stored in it for good, so if you still need that data, copy it somewhere first. To copy it into a table that already exists, add a rawSql operation running an INSERT ... SELECT before the dropColumn call in migration.ts. Then recompile the migration by running node migrations/app/20260707T1010_rollback_display_name/migration.ts from your project root, so that your edit reaches the file db migrate actually runs.
  2. Revert the change in your contract. Your contract describes the database you want, so undoing the change in the database means undoing it in the contract too: remove displayName from your contract file, then run npx prisma contract emit, the command that replaces prisma generate and rewrites contract.json. Step 4 depends on this, because db migrate applies migrations until the database matches the state recorded in contract.json.
  3. Commit the migration and the contract together. The two only make sense as a pair, so put them in one commit: the new migration's directory, your contract file, contract.json, and contract.d.ts. No new directory appears under migrations/snapshots/, which is expected, because a rollback ends at a contract state that already has one.
  4. Apply the rollback. In CI and production, run npx prisma db migrate, the command that replaces migrate deploy. In development, add --advance-ref db so that the next migration plan starts from what you just applied.

Once you have applied the rollback, npx prisma db verify passes, which confirms the database matches your reverted contract. A database that never had add_display_name applied needs neither that migration nor its rollback, and it runs neither, because db migrate runs the fewest migrations that end at the contract state you asked for.

Undoing several migrations at once works the same way. Plan one migration with npx prisma migration plan --from <newest-migration-dir> --to "<oldest-migration-to-undo>^" --name rollback_changes, then follow the same steps. The difference is step 2, where instead of deleting a single field you restore your whole contract file from a commit made before the oldest migration you are undoing, for example with git checkout <commit> -- src/prisma/contract.prisma.

✔ Planned 1 operation(s)

migrations/app/20260707T1010_rollback_display_name

└─ ⚠ Drop column "displayName" from "user"

⚠ This migration contains destructive operations that may cause data loss.

from:       866ab885a8a4bd8d9f5adc47784c068be7895a7182c55cc29f9f9967d3019484

to:         967cb9f63587c1d90f64716780f04eec22b263424e89f07139233fc2c3d710c4

app space:  migrations/app/20260707T1010_rollback_display_name

ℹ DDL preview

ALTER TABLE "public"."user" DROP COLUMN "displayName";

Read the migration before you apply it, because db migrate runs destructive operations without asking you to confirm, and this one drops a column. Open its migration.ts, and run npx prisma migration show 20260707T1010_rollback_display_name to see its SQL. When you are happy with it, complete the rollback in this order:

  1. Save the data, if you need it. Dropping the column deletes what was stored in it for good, so if you still need that data, copy it somewhere first. To copy it into a table that already exists, add a rawSql operation running an INSERT ... SELECT before the dropColumn call in migration.ts. Then recompile the migration by running node migrations/app/20260707T1010_rollback_display_name/migration.ts from your project root, so that your edit reaches the file db migrate actually runs.
  2. Revert the change in your contract. Your contract describes the database you want, so undoing the change in the database means undoing it in the contract too: remove displayName from your contract file, then run npx prisma contract emit, the command that replaces prisma generate and rewrites contract.json. Step 4 depends on this, because db migrate applies migrations until the database matches the state recorded in contract.json.
  3. Commit the migration and the contract together. The two only make sense as a pair, so put them in one commit: the new migration's directory, your contract file, contract.json, and contract.d.ts. No new directory appears under migrations/snapshots/, which is expected, because a rollback ends at a contract state that already has one.
  4. Apply the rollback. In CI and production, run npx prisma db migrate, the command that replaces migrate deploy. In development, add --advance-ref db so that the next migration plan starts from what you just applied.

Once you have applied the rollback, npx prisma db verify passes, which confirms the database matches your reverted contract. A database that never had add_display_name applied needs neither that migration nor its rollback, and it runs neither, because db migrate runs the fewest migrations that end at the contract state you asked for.

Undoing several migrations at once works the same way. Plan one migration with npx prisma migration plan --from <newest-migration-dir> --to "<oldest-migration-to-undo>^" --name rollback_changes, then follow the same steps. The difference is step 2, where instead of deleting a single field you restore your whole contract file from a commit made before the oldest migration you are undoing, for example with git checkout <commit> -- src/prisma/contract.prisma.

The first migration you plan after a rollback prints a warning when you do not pass --from, even if you applied the rollback with --advance-ref db:

⚠ The default origin ref 'db' points at 967cb9f63587c1d90f64716780f04eec22b263424e89f07139233fc2c3d710c4, which already has a migration leading to 866ab885a8a4bd8d9f5adc47784c068be7895a7182c55cc29f9f9967d3019484. Planning from it forks the migration graph; pass --from to choose the origin explicitly.

Without --from, migration plan starts from the db ref, the file in migrations/app/refs/ naming the contract state you last applied in development. After a rollback that state already has a migration starting from it, because the rollback ends at exactly the state add_display_name starts from. The migration is planned anyway, and it starts from the state the rollback ended at, so you can keep it. To plan without the warning, pass --from with the rollback's directory name:

bunx prisma migration plan --from 20260707T1010_rollback_display_name --name add_nickname
Bash
pnpm prisma migration plan --from 20260707T1010_rollback_display_name --name add_nickname
Bash
yarn prisma migration plan --from 20260707T1010_rollback_display_name --name add_nickname
Bash
npx prisma migration plan --from 20260707T1010_rollback_display_name --name add_nickname

Once you apply this migration with --advance-ref db, the db ref names a state that no migration starts from, and migration plan no longer prints the warning.

Once you apply this migration with --advance-ref db, the db ref names a state that no migration starts from, and migration plan no longer prints the warning.

When a migration fails, db migrate stops at the operation that failed rather than carrying on, and it tells you which operation it was and why:

✘ [MIGRATION.RUNNER_FAILED] Operation alterNullability.setNotNull.user.nickname failed during precheck: ensure no NULL values in "nickname"

  why: Migration runner failed

  docs: https://docs.prisma.io/docs/orm/v8/reference/error-reference/MIGRATION.RUNNER_FAILED

How much a failed run leaves behind depends on your database, and when something goes wrong explains what you are left to clean up on PostgreSQL and on MongoDB before you try again.

  1. Read which check failed. The error tells you where the run stopped, because it names the operation and the check that failed, and a precheck is a check that runs before its operation rather than after. In the example above, the precheck found rows with NULL in nickname, so the run stopped before setting the column to NOT NULL.
  2. Fix the cause, then run npx prisma db migrate again. Re-running the same command is the whole of recovery, because there is no migrate resolve step first, and in development you add --advance-ref db as usual. Sometimes the cause is the environment, such as a PostgreSQL extension the server lacks or permissions it is missing. Sometimes it is the migration itself, which is why a migration can pass in development and fail in production, where the data is different. In the example above the data is what stopped the run, so you would edit the migration to fill in nickname for existing rows before the setNotNull, recompile as in the rollback's step 1, and apply again.

Drift is what you have when your database no longer matches what your migrations say it should. The marker is the record in the database of which contract state that database matches, and which kind of drift you have depends on whether the marker is part of the problem.

In the first kind, the marker records a contract state that no migration ends at. You usually get there through npx prisma db update, which makes a database match your contract without a migration. The next db migrate fails with an error whose code is MIGRATION.MARKER_MISMATCH before it runs any operation. To fix it, write the migration your history is missing before you change the contract again: run npx prisma migration plan --from <newest-migration-dir> --name <name>. That migration ends at the state db update applied, so the next db migrate there has nothing to run.

In the second kind, only tables or columns changed, for example with a hand-run ALTER. The marker still records the last contract state applied, so db migrate still runs. It skips an operation whose change is already in the database, and it fails if an operation's check fails, or if your contract describes something missing or different once the operations have run.

Before you decide what to do about drift, find out which contract state the database matches. These commands only read, and both connect to db.connection in prisma.config.ts, or to the URL you pass with --db:

  • npx prisma migration status shows you the contract state the marker records, labeled @db, which despite the name is not the db ref.
  • npx prisma db verify checks both the marker and the tables against your contract, and lists each difference under Schema issues. Pass --schema-only when you want it to check the tables alone.

When a change was made by hand, you have to decide whether you want to keep it, and either answer gives you a way out:

  • Undo it. Change the tables back by hand until npx prisma db verify --schema-only --strict passes. The marker never changed, so there is nothing else you need to put right.
  • Keep it. Add the change to your contract, run npx prisma contract emit, then plan and apply a migration as usual. db migrate skips the change you already made there.

npx prisma db sign fixes neither kind of drift, because it is for baselining a database that has no marker at all but whose tables already match your contract. For a database that Prisma ORM 7 migrated, follow step 4 of the upgrade guide instead.

Projects created with npm create prisma@latest include the Prisma ORM skills, instruction files for your coding agent. In an existing project, run npx prisma skills sync. Ask your agent to:

  • "Plan a rollback for the last migration and show me its destructive operations."
  • "This db migrate run failed. Read the error, fix the migration, and re-run it."
  • "Check whether staging has drifted from the contract and explain the differences."
Suggest an edit

Propose a replacement for this page. The site team reviews it before applying any changes.

Export
Documentation menu