Skip to main content
Prisma Next migrations are contract-driven: you change your contract, emit it, plan the migration offline, fill in any data transforms, then apply to the database. Every migration package is fully attested on disk — a content-addressed migrationHash in migration.json means the runner can detect hand-edits or partial writes before applying anything.

The migration workflow

1

Bootstrap a new database with db init

For a fresh database, db init plans and applies all additive operations needed to bring an empty database up to your current contract, then writes the contract marker:
Use --dry-run to preview the plan without touching the database:
db init is additive-only — it creates missing tables, columns, constraints, and indexes. It will not rename or drop anything. If your database already has a marker that does not match the current contract, db init will refuse and ask you to use the migration workflow instead.
2

Update the contract after schema changes

After editing your schema, emit a fresh contract.json and contract.d.ts:
This does not connect to the database. It is a pure compilation step that produces deterministic artifacts from your schema definition.
3

Plan a migration

migration plan diffs the latest on-disk migration state against the newly emitted contract and scaffolds a new migration package. No database connection is needed:
This writes four files under migrations/<timestamp>-add-order-status/:Use --from <hash> to branch from a specific contract hash rather than the latest migration target:
4

Fill in placeholder() slots if needed

When the planner cannot lower a data transform automatically (for example, backfilling a new non-nullable column), it inserts a placeholder() slot in migration.ts. Open the file and replace the placeholder with your implementation:
After editing, re-emit ops.json and update the migrationHash by running the file directly with Node:
This regenerates ops.json with your transform included and reattests migration.json. If any placeholder() slot is still unfilled, the script exits with PN-MIG-2001.
5

Apply migrations to the database

migration apply reads the migration graph from disk, determines which migrations are pending relative to the database marker, and executes them in order. Each migration runs in its own transaction:
If a migration fails, previously applied migrations are preserved. Re-running migration apply resumes from the last successful migration.Use --ref to target a named environment ref rather than the current contract hash:
6

Inspect migration status

migration status shows the migration graph and how the database marker relates to it:
Output includes ◄ DB, ◄ Contract, and ◄ ref:<name> markers so you can see exactly where each environment sits in the graph.
7

Create named refs for multi-environment workflows

Named refs map logical environment names (such as staging or production) to specific contract hashes. Use them to route migration apply and migration status to the right point in the graph for each environment:
Refs are stored in migrations/refs.json and written atomically to prevent corruption.

Migration integrity: hash attestation

Every migration package on disk is fully attested. migration.json contains a migrationHash that is computed over (metadata, ops). When migration apply loads packages, it rehashes each one and confirms the result matches the stored hash. If a package has been hand-edited or partially written, the load fails with MIGRATION.HASH_MISMATCH and points at the offending directory:
This means the runner never executes a migration that has silently diverged from what was planned and reviewed.

db init vs db update

db update allows destructive operations (renaming columns, dropping tables) in addition to additive ones. In interactive mode you will be prompted to confirm; in non-interactive mode you must pass -y / --yes. Review the plan carefully before confirming — destructive operations can cause data loss.
db init is the safe default for new databases. db update is the escape hatch for databases that were not initialized through the migration workflow, or for quick local resets. For production, prefer migration plan → migration apply to keep a full audit trail in version control.