# Generating a migration (/docs/orm/migrations/generating-a-migration)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Turn a change to your contract into a migration you can review, with the migration plan command.

Location: ORM > Migrations > Generating a migration

This tutorial takes a change you have made to your contract, the `contract.prisma` file that replaced `schema.prisma`, and turns it into a migration that you read and approve before it runs against a database. To create a project first, see the [quickstart](https://www.prisma.io/docs/prisma-orm/quickstart/postgresql).

Two commands do the work, and you run them in this order every time you change your contract. `npx prisma contract emit` replaces `prisma generate`: it reads `contract.prisma` and writes `contract.json` and `contract.d.ts` next to it, so that everything downstream reads your latest edit and not the version before it. `npx prisma migration plan` then reads `contract.json` and writes a new migration for the change, without applying it. Planning never connects to a database, which means you can run it in CI or in a sandbox with no database credentials. To work out what your change is a change from, `migration plan` looks by default at the `db` [ref](https://www.prisma.io/docs/orm/migrations/the-migration-graph#terms-used-on-this-page), a file in `migrations/app/refs/` that records the contract version you last applied in development.

## Your first migration [#your-first-migration]

Say your contract has a single model:

```prisma title="contract.prisma"
model User {
  id    Int     @id
  email String
  name  String?

  @@map("user")
}
```

Run both commands, passing `--name init` so that the new migration directory is named `<timestamp>_init`:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name init
```

#### pnpm

```bash
pnpm dlx prisma contract emit
pnpm dlx prisma migration plan --name init
```

#### yarn

```bash
yarn dlx prisma contract emit
yarn dlx prisma migration plan --name init
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name init
```

```text
│  contract:    src/prisma/contract.json
│  migrations:  migrations/app
│  name:        init

✔ Planned 2 operation(s)
ℹ No db ref set — planning from an empty database. Run db init, db update, or db sign if a database already exists.

migrations/app/20260707T1005_init
├─ Create schema "public"
└─ Create table "user"

from:       (baseline)
to:         705b1a62f26f0913caa4bfe3f8b7cb491a1b94bd47fc43471d8711bc480bcbb5
app space:  migrations/app/20260707T1005_init

ℹ DDL preview

CREATE SCHEMA IF NOT EXISTS "public";
CREATE TABLE "public"."user" (
  "email" text NOT NULL,
  "id" int4 NOT NULL,
  "name" text,
  PRIMARY KEY ("id")
);
```

Read the rest of that output closely, because it tells you what was planned and where it was written:

* **`Planned 2 operation(s)`** counts the steps in the migration, which are listed underneath the directory name, and the DDL preview below them is the SQL those steps run.
* **`to:`** is the hash of your contract. Each version of your contract is a contract state, and Prisma ORM identifies a state by that hash rather than by a version number.
* **`from: (baseline)`** tells you this is a baseline migration, meaning a first migration that goes from an empty database to a contract state. What Prisma ORM 7 called baselining, marking an existing database as already migrated, is a separate command in Prisma ORM 8, `npx prisma db sign`.
* **`app space:`** is the directory the new migration was written to. Your app's migrations are in `migrations/app/`, and each [Prisma ORM extension package](https://www.prisma.io/docs/orm/extensions/using-extensions) that ships migrations gets a directory of its own beside it. Prisma ORM looks for `migrations/` in the directory you run commands from, which is normally the project root.

The `No db ref set` line is telling you that nothing in this project records which contract state your database matches, so `migration plan` assumed an empty database and planned from there. That assumption is right for a new project. If you already have a database, tell Prisma ORM what is in it before you plan anything, and which command does that depends on what the database holds:

* If Prisma ORM 7 migrated the database, follow the steps in the [upgrade guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql#4-transfer-migration-ownership) first.
* If the database is empty, you need nothing: `npx prisma db migrate` creates the tables for you, though it does not create the database itself.
* If every table in the database already matches your contract, run [`npx prisma db sign`](https://www.prisma.io/docs/cli/db-sign) and then read [The automatic baseline](#the-automatic-baseline) below. `db sign` checks the tables against your contract and then writes the [marker](https://www.prisma.io/docs/orm/migrations/the-migration-graph#terms-used-on-this-page), which is the record in the database of which contract state it matches.
* If the database has only some of your tables, run [`npx prisma db init`](https://www.prisma.io/docs/cli/db-init). It adds what is missing and nothing else, and it stops if matching your contract would need a change that could lose data, such as dropping a column.
* If this is a development or preview database that you want to match your contract without keeping migration files for it, run [`npx prisma db update`](https://www.prisma.io/docs/cli/db-update). Unlike `db init`, it will make changes that could lose data, so it asks you to type the database name first.

A migration is a directory, and there is no SQL file in it. It holds three files instead: `migration.ts`, which is the one you read and sometimes edit, plus `ops.json` and `migration.json`, which are what `db migrate` reads when it applies the migration. Commit all three, along with `contract.prisma`, `contract.json`, `contract.d.ts`, and any new directories under `migrations/snapshots/`, which are saved copies of your contract. The change itself is in `migration.ts`, written as a list of method calls:

```ts title="migrations/app/20260707T1005_init/migration.ts"
#!/usr/bin/env -S node
import type { Contract as End } from '../../snapshots/705b1a62f26f0913caa4bfe3f8b7cb491a1b94bd47fc43471d8711bc480bcbb5/contract';
import endContract from '../../snapshots/705b1a62f26f0913caa4bfe3f8b7cb491a1b94bd47fc43471d8711bc480bcbb5/contract.json' with { type: 'json' };
import { Migration, MigrationCLI, col, primaryKey } from '@prisma/orm-postgres/migration';

export default class M extends Migration<never, End> {
  override readonly endContractJson = endContract;

  override get operations() {
    return [
      this.createSchema({ schema: 'public' }),
      this.createTable({
        schema: 'public',
        table: 'user',
        columns: [
          col('email', 'text', { notNull: true, codecRef: { codecId: 'pg/text@1' } }),
          col('id', 'int4', { notNull: true, codecRef: { codecId: 'pg/int4@1' } }),
          col('name', 'text', { codecRef: { codecId: 'pg/text@1' } }),
        ],
        constraints: [primaryKey(['id'])],
      }),
    ];
  }
}

MigrationCLI.run(import.meta.url, M);
```

Everything the migration will do is in that `operations` list, so reading it tells you exactly what will happen, and editing it is how you change what happens. A change as simple as this one needs no edit, and `ops.json` is never a file you edit by hand. [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration) covers the cases where you do edit `migration.ts` and recompile it, such as adding a data backfill, reordering operations, or running raw SQL.

## The second migration: planning a delta [#the-second-migration-planning-a-delta]

Apply that first migration to your development database by running `npx prisma db migrate --advance-ref db`. This is the first command here that connects to a database, and it uses [`db.connection`](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract) in `prisma.config.ts` unless you pass a connection string with `--db`. The `--advance-ref db` part is what records the result: it points the `db` ref at the contract state you just applied, so the next time you run `migration plan` it starts from there and plans only what has changed since.

Now add an optional `phone String?` field to `User`, and run both commands again:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_user_phone
```

#### pnpm

```bash
pnpm dlx prisma contract emit
pnpm dlx prisma migration plan --name add_user_phone
```

#### yarn

```bash
yarn dlx prisma contract emit
yarn dlx prisma migration plan --name add_user_phone
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_user_phone
```

```text
│  contract:    src/prisma/contract.json
│  migrations:  migrations/app
│  name:        add_user_phone

✔ Planned 1 operation(s)

migrations/app/20260707T1006_add_user_phone
└─ Add column "phone" to "user"

from:       705b1a62f26f0913caa4bfe3f8b7cb491a1b94bd47fc43471d8711bc480bcbb5
to:         925198f3cc272c5fd19c24ac02f251661775ddac21cdac4e634bbc0dda8b2d72
app space:  migrations/app/20260707T1006_add_user_phone

ℹ DDL preview

ALTER TABLE "public"."user" ADD COLUMN "phone" text;
```

To plan from a contract state other than the one the `db` ref names, say which one with `--from`, as in `--from 20260707T1005_init`. When you give `--from` a migration directory name, you are naming the contract state that exists once that migration has run. The [`migration plan` reference](https://www.prisma.io/docs/cli/migration-plan#options) lists every form the flag accepts.

### The db ref: skipping --from [#the-db-ref-skipping---from]

Once your first migration is applied, every change you make after that follows the same routine, which does the job `migrate dev` did in Prisma ORM 7 whenever you wanted migration files out of it, as the [command table](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#commands) shows:

1. Edit your contract.
2. Run `npx prisma contract emit`. If you skip this, `migration plan` reads the `contract.json` from before your edit, so it either prints `No changes detected` or plans a migration that is missing your latest change.
3. Run `npx prisma migration plan --name <name>`.
4. Review what it planned with `npx prisma migration show <dir>`, where `<dir>` is the new migration's directory name. If you edit `migration.ts`, you then have to [recompile it](https://www.prisma.io/docs/orm/migrations/editing-a-migration) by running `node migrations/app/<dir>/migration.ts` from your project root, which rewrites `ops.json` and `migration.json` to match what you edited.
5. Apply it. In development that is `npx prisma db migrate --advance-ref db`, and in CI and production it is `npx prisma db migrate` without the flag.

The step that is easy to get out of order is the last one, and the symptom is a migration that repeats work you already planned. If you plan a second migration before you have applied the first one with `--advance-ref db`, the `db` ref still names the older contract state, so Prisma ORM plans the first migration's changes a second time. To fix that, delete the directory of the repeated migration, run [`npx prisma migration ref set db <dir>`](https://www.prisma.io/docs/cli/migration-ref) with the name of the directory whose changes it repeated, and plan again. Deleting the directory is how you discard any migration that has not run on a database, and the matching directory under `migrations/snapshots/` can stay.

`db migrate --advance-ref db` is not the only command that updates the `db` ref. When `npx prisma db sign`, `db init`, and `db update` change the database configured in `prisma.config.ts`, they point the `db` ref at the new state as well. `db sign` is the one to watch, because it updates the ref even when you pass `--db` to sign a different database, so add `--no-advance-ref` when you do.

When you leave `--from` off, what `migration plan` does depends on whether `migrations/app/` already has migrations in it and whether the `db` ref exists. The combinations are:

| Migrations in `migrations/app/` | `db` ref | What `migration plan` does                    |
| ------------------------------- | -------- | --------------------------------------------- |
| None                            | None     | Plans from an empty database                  |
| None                            | Exists   | Writes a baseline migration, then your change |
| Some                            | Exists   | Plans from the state the `db` ref points at   |
| Some                            | None     | Stops with an error                           |

That last row is an error because Prisma ORM has migrations but nothing recording which contract state your database matches, and it will not guess. The error prints the commands that resolve it: one sets the `db` ref, one plans with `--from`, and one plans with `--from @empty`.

### The automatic baseline [#the-automatic-baseline]

If you started from an existing database, `db sign` and `db update` leave you in the second row of that table: you have no migration files yet, but the `db` ref names a contract state. What that means in practice is that you should run `migration plan` before you ever run `db migrate`. Planning writes a baseline migration ending at the state your database already matches, plus a second migration for your own change if `contract.json` has changed since. You need that baseline because `db migrate` fails against the database until one migration's `to:` hash matches the marker, and it never runs the baseline there, since the marker already records that the database matches that state. [Baselines](https://www.prisma.io/docs/orm/migrations/the-migration-graph#baselines) has the full rule.

There is one situation where that automatic baseline is not the one you want. If a deployed database, such as production, matches an older version of your contract than your development database does, a baseline planned the usual way would end at your development database's contract state, which is not the state production matches. Plan the baseline from the older version instead:

1. Change your contract back to the deployed version, for example with `git show <commit>:<contract path> > <contract path>`.
2. Run `npx prisma contract emit`.
3. Run `npx prisma migration plan --name baseline --from @empty`.
4. Run `npx prisma db sign --db "$PRODUCTION_DATABASE_URL" --no-advance-ref` against the deployed database. It writes the marker there, and `--no-advance-ref` leaves your `db` ref alone.
5. Restore your current contract and run `npx prisma contract emit` again.
6. Plan the change with `npx prisma migration plan --name <name> --from <baseline dir>`, the baseline's directory name.

None of these steps changes your `db` ref.

## When the planner needs your input [#when-the-planner-needs-your-input]

Some changes cannot be planned in full, because the answer depends on your data rather than on your contract. Adding a **required** field with no default to a table that already has rows is the common one: `migration plan` writes the `ADD COLUMN` and the `SET NOT NULL`, but only you know what the rows that already exist should contain, so it leaves that part for you to fill in as a **placeholder**. To see one, apply `add_user_phone`, then add a required `displayName String` field to `User` and run both commands again:

  

#### bun

```bash
bunx prisma contract emit
bunx prisma migration plan --name add_display_name
```

#### pnpm

```bash
pnpm dlx prisma contract emit
pnpm dlx prisma migration plan --name add_display_name
```

#### yarn

```bash
yarn dlx prisma contract emit
yarn dlx prisma migration plan --name add_display_name
```

#### npm

```bash
npx prisma contract emit
npx prisma migration plan --name add_display_name
```

```text
│  contract:    src/prisma/contract.json
│  migrations:  migrations/app
│  name:        add_display_name

⚠ Planned migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit

from:       925198f3cc272c5fd19c24ac02f251661775ddac21cdac4e634bbc0dda8b2d72
to:         e6b5c2849eca8d24ff1e8e88ab2a4234db8e74c497c035cb7ce42e814f31cd63
app space:  migrations/app/20260707T1008_add_display_name
```

Open the new `migration.ts` and you will find a `dataTransform` step between the `ADD COLUMN` and the `SET NOT NULL`, which is the step that updates the rows already in the table. The two `placeholder(...)` calls inside it mark where your queries go: the first finds the rows that still need a `displayName`, and the second fills the value in. Write both with the [SQL query builder](https://www.prisma.io/docs/orm/reference/sql-query-builder), as [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration) shows, and then recompile the file, which is the step the output above calls self-emit. Nothing can be applied until you do, because `migration plan` leaves `ops.json` empty when it writes placeholders, so `db migrate` fails and changes nothing.

## Reviewing what you planned [#reviewing-what-you-planned]

You can inspect a planned migration before anything runs, with these commands, none of which connects to a database:

  

#### bun

```bash
# One migration in detail: operations, metadata, DDL preview
bunx prisma migration show 20260707T1006_add_user_phone
# The whole migration history, with your new migration in place
bunx prisma migration graph
# Integrity check: hashes match, no files missing, every migration starts from empty or where another ends, refs point at known states
bunx prisma migration check
```

#### pnpm

```bash
# One migration in detail: operations, metadata, DDL preview
pnpm dlx prisma migration show 20260707T1006_add_user_phone
# The whole migration history, with your new migration in place
pnpm dlx prisma migration graph
# Integrity check: hashes match, no files missing, every migration starts from empty or where another ends, refs point at known states
pnpm dlx prisma migration check
```

#### yarn

```bash
# One migration in detail: operations, metadata, DDL preview
yarn dlx prisma migration show 20260707T1006_add_user_phone
# The whole migration history, with your new migration in place
yarn dlx prisma migration graph
# Integrity check: hashes match, no files missing, every migration starts from empty or where another ends, refs point at known states
yarn dlx prisma migration check
```

#### npm

```bash
# One migration in detail: operations, metadata, DDL preview
npx prisma migration show 20260707T1006_add_user_phone
# The whole migration history, with your new migration in place
npx prisma migration graph
# Integrity check: hashes match, no files missing, every migration starts from empty or where another ends, refs point at known states
npx prisma migration check
```

`migration check` is the one to run in CI, where you read its exit code rather than its output. `0` means every check passed, `4` means an integrity failure such as a missing file or an `ops.json` that someone edited by hand, and `2` means it could not find a migration you named. There is one thing it cannot tell you, because it never reads `migration.ts`: whether you remembered to recompile after your last edit. You can check that yourself by staging the migration with `git add` and then recompiling it, because if `git status` afterwards shows no unstaged change to `ops.json` or `migration.json`, they were already up to date. This does not work for a backfill on a model with an [`updatedAt` column](https://www.prisma.io/docs/orm/migrations/editing-a-migration#worked-example-making-a-column-required).

> [!NOTE]
> What's early
> 
> Planning covers tables, columns, indexes, constraints, and the backfill placeholder shown above. What it cannot do yet is notice that you renamed something: if you rename an optional field, it plans the change as **drop column + add column**, and `migration plan` prints a warning that the change can lose data. Take that warning seriously, because `db migrate` runs destructive operations without asking, so read `migration show <dir>` before you apply anything. To rename a column and keep the data in it, edit `migration.ts`, replace that pair of operations with a [`rawSql` operation](https://www.prisma.io/docs/orm/migrations/editing-a-migration#escape-hatch-raw-sql) that runs `ALTER TABLE ... RENAME COLUMN`, and recompile. One more difference from Prisma ORM 7: `migration plan` never asks you questions the way `migrate dev` did.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent. In an existing project, run `npx prisma skills sync`. The skills are instruction files your agent reads, so you can ask it to:

* "Add a required `displayName` field to User, emit the contract, and plan the migration."
* "Plan a migration named `add-orders-table` and show me its DDL preview before I commit it."
* "Run `migration check` and explain any integrity failures."

## See also [#see-also]

* [Editing a migration](https://www.prisma.io/docs/orm/migrations/editing-a-migration): fill placeholders, add data steps, write raw SQL
* [Applying a migration](https://www.prisma.io/docs/orm/migrations/applying-a-migration): run what you planned
* [Studio with Prisma ORM](https://www.prisma.io/docs/studio/prisma-next): once applied, see the same operations as a visual diff in Prisma Studio
* [TypeScript Migrations in Prisma 8](https://www.prisma.io/blog/typescript-migrations-in-prisma-next): a blog post on the design of `migration.ts`

## Related pages

- [`Applying a migration`](https://www.prisma.io/docs/orm/migrations/applying-a-migration): The db migrate command applies the migrations you planned, until your database matches your contract, with a preview, checks on every operation, and safe re-runs.
- [`Editing a migration`](https://www.prisma.io/docs/orm/migrations/editing-a-migration): A migration is TypeScript you own. Fill in backfills, reorder steps, or write raw SQL, then recompile it with one command.
- [`How migrations work`](https://www.prisma.io/docs/orm/migrations/how-migrations-work): Change your contract, plan a migration, review it, apply it. Operations can check the database before and after they run.
- [`Rollbacks and recovery`](https://www.prisma.io/docs/orm/migrations/rollbacks-and-recovery): Rolling back is one more migration that makes the database match an earlier contract state. Recovery is fixing a failed migration and running it again.
- [`The migration graph`](https://www.prisma.io/docs/orm/migrations/the-migration-graph): You and a teammate each changed your Prisma contract on separate branches. The migration graph is how Prisma ORM applies both changes to every database after the branches merge.