@prisma/orm-mongo 8.0.0-rc.1-dev.46 → 8.0.0-rc.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +1 -5
  2. package/dist/contract-builder.d.mts +1 -0
  3. package/dist/contract-builder.d.mts.map +1 -1
  4. package/dist/utils__suppress-idle-connection-errors.d.mts +1 -0
  5. package/dist/utils__suppress-idle-connection-errors.mjs +2 -0
  6. package/package.json +14 -12
  7. package/skills/prisma-8/SKILL.md +96 -0
  8. package/skills/prisma-8/references/build.md +142 -0
  9. package/skills/prisma-8/references/contract.md +446 -0
  10. package/skills/prisma-8/references/debug.md +144 -0
  11. package/skills/prisma-8/references/feedback.md +251 -0
  12. package/skills/prisma-8/references/migration-model.md +175 -0
  13. package/skills/prisma-8/references/migration-review.md +241 -0
  14. package/skills/prisma-8/references/migrations.md +538 -0
  15. package/skills/prisma-8/references/queries-mongo.md +236 -0
  16. package/skills/prisma-8/references/queries-postgres.md +415 -0
  17. package/skills/prisma-8/references/queries.md +237 -0
  18. package/skills/prisma-8/references/quickstart.md +317 -0
  19. package/skills/prisma-8/references/runtime.md +366 -0
  20. package/skills/prisma-8/references/supabase.md +231 -0
  21. package/skills/prisma-8/references/upgrade-app.md +101 -0
  22. package/skills/prisma-8/references/upgrade-extension.md +105 -0
  23. package/skills/prisma-8/upgrading/app/upgrades/0.10-to-0.11/instructions.md +56 -0
  24. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/instructions.md +381 -0
  25. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/re-emit-closed-mongo-contracts.ts +202 -0
  26. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/re-emit-domain-namespaced-contracts.ts +201 -0
  27. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/re-emit-postgres-public-default.ts +198 -0
  28. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/strip-migration-labels-hints.ts +340 -0
  29. package/skills/prisma-8/upgrading/app/upgrades/0.12-to-0.13/instructions.md +339 -0
  30. package/skills/prisma-8/upgrading/app/upgrades/0.12-to-0.13/re-emit-mti-variant-link-columns.ts +229 -0
  31. package/skills/prisma-8/upgrading/app/upgrades/0.13-to-0.14/instructions.md +543 -0
  32. package/skills/prisma-8/upgrading/app/upgrades/0.13-to-0.14/migration-op-factories-to-methods.ts +290 -0
  33. package/skills/prisma-8/upgrading/app/upgrades/0.13-to-0.14/uuid-preset-rename.ts +43 -0
  34. package/skills/prisma-8/upgrading/app/upgrades/0.14-to-0.15/instructions.md +359 -0
  35. package/skills/prisma-8/upgrading/app/upgrades/0.15-to-0.16/instructions.md +173 -0
  36. package/skills/prisma-8/upgrading/app/upgrades/0.16-to-0.17/instructions.md +805 -0
  37. package/skills/prisma-8/upgrading/app/upgrades/0.16-to-0.17/strip-sha256-hash-prefixes.ts +382 -0
  38. package/skills/prisma-8/upgrading/app/upgrades/0.17-to-8.0.0-rc.1/instructions.md +72 -0
  39. package/skills/prisma-8/upgrading/app/upgrades/0.7-to-0.8/instructions.md +8 -0
  40. package/skills/prisma-8/upgrading/app/upgrades/0.8-to-0.9/instructions.md +36 -0
  41. package/skills/prisma-8/upgrading/app/upgrades/0.8-to-0.9/strip-inline-contracts.ts +226 -0
  42. package/skills/prisma-8/upgrading/app/upgrades/0.9-to-0.10/instructions.md +86 -0
  43. package/skills/prisma-8/upgrading/app/upgrades/0.9-to-0.10/stamp-storage-types-kind.ts +360 -0
  44. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.1-to-8.0.0-rc.2/instructions.md +588 -0
  45. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.2-to-8.0.0-rc.3/instructions.md +5 -0
  46. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.3-to-8.0.0-rc.4/instructions.md +158 -0
  47. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.4-to-8.0.0-rc.5/instructions.md +42 -0
  48. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.5-to-8.0.0-rc.6/instructions.md +157 -0
  49. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.6-to-8.0.0-rc.7/instructions.md +33 -0
  50. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.7-to-8.0.0-rc.8/instructions.md +36 -0
  51. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.8-to-8.0.0-rc.9/instructions.md +63 -0
  52. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.9-to-8.0.0-rc.10/instructions.md +84 -0
  53. package/skills/prisma-8/upgrading/extension/upgrades/0.10-to-0.11/instructions.md +276 -0
  54. package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/instructions.md +738 -0
  55. package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/migrate-contract-testing-imports.ts +97 -0
  56. package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/regenerate-extension-public-baseline.ts +223 -0
  57. package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/strip-migration-labels-hints.ts +340 -0
  58. package/skills/prisma-8/upgrading/extension/upgrades/0.12-to-0.13/instructions.md +266 -0
  59. package/skills/prisma-8/upgrading/extension/upgrades/0.13-to-0.14/instructions.md +522 -0
  60. package/skills/prisma-8/upgrading/extension/upgrades/0.13-to-0.14/migration-op-factories-to-methods.ts +290 -0
  61. package/skills/prisma-8/upgrading/extension/upgrades/0.13-to-0.14/uuid-preset-rename.ts +43 -0
  62. package/skills/prisma-8/upgrading/extension/upgrades/0.14-to-0.15/instructions.md +803 -0
  63. package/skills/prisma-8/upgrading/extension/upgrades/0.15-to-0.16/instructions.md +219 -0
  64. package/skills/prisma-8/upgrading/extension/upgrades/0.16-to-0.17/instructions.md +731 -0
  65. package/skills/prisma-8/upgrading/extension/upgrades/0.16-to-0.17/strip-sha256-hash-prefixes.ts +382 -0
  66. package/skills/prisma-8/upgrading/extension/upgrades/0.17-to-8.0.0-rc.1/instructions.md +194 -0
  67. package/skills/prisma-8/upgrading/extension/upgrades/0.7-to-0.8/instructions.md +8 -0
  68. package/skills/prisma-8/upgrading/extension/upgrades/0.8-to-0.9/instructions.md +57 -0
  69. package/skills/prisma-8/upgrading/extension/upgrades/0.8-to-0.9/strip-inline-contracts.ts +226 -0
  70. package/skills/prisma-8/upgrading/extension/upgrades/0.9-to-0.10/instructions.md +150 -0
  71. package/skills/prisma-8/upgrading/extension/upgrades/0.9-to-0.10/stamp-storage-types-kind.ts +360 -0
  72. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.1-to-8.0.0-rc.2/instructions.md +746 -0
  73. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.2-to-8.0.0-rc.3/instructions.md +5 -0
  74. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.3-to-8.0.0-rc.4/instructions.md +137 -0
  75. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.4-to-8.0.0-rc.5/instructions.md +129 -0
  76. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.5-to-8.0.0-rc.6/instructions.md +102 -0
  77. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.6-to-8.0.0-rc.7/instructions.md +33 -0
  78. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.7-to-8.0.0-rc.8/instructions.md +35 -0
  79. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.8-to-8.0.0-rc.9/instructions.md +86 -0
  80. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.9-to-8.0.0-rc.10/instructions.md +63 -0
@@ -0,0 +1,538 @@
1
+
2
+ # Prisma 8 — Migration Authoring
3
+
4
+ > **Edit your data contract. Prisma 8 plans the migration. You fill in any data transforms.**
5
+
6
+ The three-step user model:
7
+
8
+ 1. **You edit your data contract.** (`references/contract.md`)
9
+ 2. **Prisma 8 plans the migration for you.** ← this skill
10
+ 3. **If a data transform is needed, you edit `migration.ts` and self-emit.** ← this skill
11
+
12
+ Once the contract changes, you choose how the change reaches the database. This skill covers the two paths (`db update` and `migration plan` + `db migrate`), the migration-package contract, the `migration.ts` authoring API, and the failure modes you recover from without leaving the loop.
13
+
14
+ **Targets.** Migration authoring is first-class for **Postgres** and **Mongo**. The CLI reads the target from `prisma.config.ts` (set during `prisma orm init --target …`). Migration commands do not accept a `--target` flag — use a config scoped to the target you need. Examples below call out target-specific imports, markers, factories, and transaction behavior where they diverge.
15
+
16
+ ## When to Use
17
+
18
+ - User edited the contract and wants to apply the change to the DB.
19
+ - User wants to author a migration with a data transform.
20
+ - User wants to run pending migrations against a local DB.
21
+ - User hit `MIGRATION.HASH_MISMATCH`, `MIGRATION.UNFILLED_PLACEHOLDER`, or a partially-applied migration.
22
+ - User mentions: *migrate, migration, db push, db update, `prisma migrate dev`, `prisma migrate deploy`, drift, hash mismatch, data backfill*.
23
+
24
+ ## When Not to Use
25
+
26
+ - User wants to know what migrations *will run on deploy* / on merge, or to manage refs and invariants → `references/migration-review.md`.
27
+ - User is deciding where a plan should chain from, saw `from: (baseline)` unexpectedly, is setting up migrations for a deploy-first (Composer / CD-managed) project, or is retrofitting migrations onto an existing database → `references/migration-model.md`.
28
+ - User wants to edit the contract → `references/contract.md`.
29
+ - User wants a deeper read of a single structured error envelope → `references/debug.md`.
30
+
31
+ ## Key Concepts
32
+
33
+ - **`db update` (quick path).** Reads the emitted contract, diffs against the live DB, applies the change. Optional `--dry-run` prints the plan without executing. A destructive operation is applied only with consent: interactively you type the database name; non-interactively pass `--confirm <database>` (`--yes` does not grant it). **Writes no migration directory.** Operations needing data transforms are not handled by this path — `db update` excludes the `data` operation class entirely and short-circuits where a data transform would be required. Use only against a database that has no shared history with anyone else (your local dev DB).
34
+ - **`migration plan` (formal path).** Reads the emitted contract, diffs it against a resolved origin — explicit `--from`, else the `db` ref, else the empty database; there is no "head of the graph" to chain from (see `references/migration-model.md`) — and writes a new migration package under `migrations/app/<YYYYMMDDTHHMM>_<snake_slug>/`. If any operation needs a data transform, the package's `migration.ts` contains `placeholder(...)` calls you fill in.
35
+ - **The `app/` segment in migration paths is the consuming application's contract-space id.** Every migration *you* author lives under `migrations/app/`. Extensions your contract depends on get their own sibling directories (`migrations/<extension-space-id>/`) — those are managed by the extension package and you don't write into them. The `app/` segment lands automatically the first time you run `migration plan` / `db init` against an app-level config.
36
+ - **Migration package files** (inside each `migrations/app/<dir>/`):
37
+ - `migration.json` — manifest (metadata + `migrationHash`).
38
+ - `ops.json` — canonical operation list. Content-addressed; `migrationHash` is computed over this.
39
+ - `migration.ts` — TypeScript authoring source, **framework-rendered** by `migration plan` (or `migration new`). You edit specific holes in it (see *Fill a placeholder* below) and re-emit `ops.json` / `migration.json` by running it.
40
+ - **Contract snapshots.** `migration.ts` imports its bookend contracts from the shared, content-addressed store at `migrations/snapshots/<hex>/contract.json` + `contract.d.ts` (`<hex>` is the contract's 64-hex storage hash) — not from files inside the migration package.
41
+ - **Self-emit.** Running `node migrations/app/<dir>/migration.ts` regenerates `ops.json` and `migration.json` from the (possibly edited) TS source. This is the only supported way to update an existing migration package after edits.
42
+ - **`migration.ts` shape.** Framework-rendered. A class `M extends Migration<Start, End>` (from `@internal/postgres/migration` on Postgres, `@prisma/orm-mongo/target/migration` on Mongo — see the framing block below) that assigns the two snapshot imports to `startContractJson` / `endContractJson` (`Start` is `never` and there is no `startContractJson` on a baseline) and has an `operations` getter returning an array of operation values. **On Postgres the operation factories are methods on the base class** (`this.addColumn({...})`, `this.setNotNull({...})`, `this.dataTransform(...)`) taking one options object; free helpers like `col(...)` build the column descriptors they take. **On Mongo they are free factories** (`createIndex(...)`, `dataTransform(...)`) imported beside `Migration`. The file ends with `MigrationCLI.run(import.meta.url, M)` so executing it self-emits.
43
+ - **`placeholder(slot)`.** A sentinel the planner emits into the rendered `migration.ts` (from the same `.../migration` import as `Migration`) wherever a data transform is needed. Calling `placeholder(...)` at emit time throws `MIGRATION.UNFILLED_PLACEHOLDER` with `meta.slot` naming the hole. The user replaces the `() => placeholder(...)` arrow with a real query-plan closure (Postgres) or fills `dataTransform({ check, run })` sources (Mongo — see *Fill a placeholder*), then self-emits.
44
+ - **`this.dataTransform(endContract, name, { check, run })`.** The data-transform factory. `check` is a rowset query whose presence-of-any-row signals "work remains"; `run` is one or more mutation queries that perform the backfill. Both are lazy closures returning query-plans built against `endContract`. The runner wraps `check` as `EXISTS(...)` for precheck and `NOT EXISTS(...)` for postcheck, so the same closure asserts both "there is work" and "the work is done".
45
+ - **`pendingPlaceholders`.** A boolean field on the JSON result of `migration plan`. `true` means the package was written but contains unfilled placeholders — `db migrate` will throw `MIGRATION.UNFILLED_PLACEHOLDER` until you edit `migration.ts` and self-emit.
46
+ - **`migrationHash`.** Content-addressed identity of a migration package. `MIGRATION.HASH_MISMATCH` fires when the stored hash in `migration.json` disagrees with the hash recomputed from the on-disk files (almost always: someone edited `migration.ts` without self-emitting).
47
+ - **Marker.** Records "this database is at contract hash X for space Y". **Postgres:** a row in `prisma_contract.marker`. **Mongo:** a document in the `_prisma_migrations` collection (keyed by space). Each successful migration advances the marker once schema verification passes for that space. `db sign` writes the marker from the current contract hash, but only after a schema-verification pass succeeds (it will not sign a database whose live schema disagrees with the contract).
48
+ - **Apply atomicity.** **Postgres:** one `db migrate` run is one transaction — the runner issues a single `BEGIN`, applies every pending migration for every contract space, then one `COMMIT`; any failure issues `ROLLBACK` for the whole run, so the marker stays where it was before the command. **Mongo:** DDL ops (`createCollection`, `createIndex`, `collMod`, `setValidation`, …) are not wrapped in a multi-document transaction; the runner applies ops, verifies the live schema against the destination contract, and advances the marker only on verify-pass (resumable across spaces — see the MongoDB family doc). Ordinary DDL + `dataTransform` flows stay consistent; partial state from failed mid-migration runs is diagnosed with `db verify` / `db schema`, not assumed away.
49
+ - **Operation classes.** Every operation declares an `operationClass`: `additive`, `widening`, `data`, or `destructive`. The CLI surfaces these in the plan preview and in JSON output. There is no `long-running` class and the framework does not emit `CREATE INDEX CONCURRENTLY` — operations stay transactional.
50
+
51
+ ## `migration.ts` is framework-rendered, not hand-authored
52
+
53
+ Files under `migrations/<space-id>/<timestamp>/migration.ts` (for your own app, `<space-id>` is always `app/`) are **rendered for you** by the framework — `prisma migration plan` writes a populated package whenever the contract changes, and `prisma migration new` writes an empty scaffold when you want to author operations directly. You do not write these files from scratch. You edit specific holes the framework leaves behind — chiefly replacing `placeholder("<slot>")` sentinels (Postgres) or filling `dataTransform({ check, run })` pipeline slots (Mongo) — then self-emit.
54
+
55
+ **Postgres** rendered imports point at `@internal/postgres/migration` (or `@internal/sqlite/migration` for SQLite projects): one line carrying `Migration`, `MigrationCLI`, `col`, `placeholder`, `rawSql`, and any other free helper the operations need.
56
+
57
+ **Mongo** rendered imports point at one module too, `@prisma/orm-mongo/target/migration`, which carries `Migration`, `MigrationCLI`, `placeholder`, and the operation factories (`createIndex`, `dataTransform`, …). Raw command classes for data transforms come from `@prisma/orm-mongo/query-ast/execution`.
58
+
59
+ Treat the rendered import lines as framework-managed on both targets:
60
+
61
+ - Leave them where they are. Don't rewrite them to a different path; the framework's renderer is the authoritative shape and any change you make by hand will be reverted (and may trip `MIGRATION.HASH_MISMATCH`) the next time the package is re-rendered or self-emitted.
62
+ - If you need an additional helper symbol, **add it to the existing rendered import line** rather than introducing a second import from a different subpath.
63
+ - The "user code imports only from `@internal/<target>`" convention applies to *your* own modules (queries, runtime setup, contract authoring). The framework-rendered `migration.ts` scaffold is the framework's surface, not yours; the rule is suspended for that one file.
64
+
65
+ ## Diagnostic codes you route on
66
+
67
+ | Code | Source | Move |
68
+ |---|---|---|
69
+ | `MIGRATION.UNFILLED_PLACEHOLDER` | Throwing `placeholder(...)` at emit time | Open `migration.ts`, replace the `placeholder("<slot>")` call named by `meta.slot` with the real query closure, self-emit. |
70
+ | `MIGRATION.FILE_MISSING` | Reading a migration package | `migration.ts`, `migration.json`, or `ops.json` is absent. Recover from version control, re-emit via `migration.ts`, or run `prisma migration new` for a fresh one. |
71
+ | `MIGRATION.INVALID_DEFAULT_EXPORT` | Loading `migration.ts` | The file's default export is not a `Migration` subclass or factory function. Restore the planner-emitted scaffold from version control or re-run `migration plan` for a clean package. |
72
+ | `MIGRATION.DATA_TRANSFORM_CONTRACT_MISMATCH` | Building a data-transform query plan | The query builder was instantiated with a contract reference different from the `endContract` passed to `this.dataTransform(...)`. Use the `endContract` imported at module scope for both. |
73
+ | `MIGRATION.HASH_MISMATCH` *Migration package is corrupt* | `db migrate` (or any read of the package) | `ops.json` / `migration.json` were edited without self-emitting. Run `node migrations/app/<dir>/migration.ts` to re-emit, then re-run `db migrate`. |
74
+ | `MIGRATION.DESTRUCTIVE_CHANGES` | `db update` run non-interactively without consent | Re-run with `--confirm <database>` (the database name from the connection), or `--dry-run` to preview. |
75
+ | `CONTRACT.MARKER_MISMATCH` | `db verify` (finding, exit 4) | The marker disagrees with the contract hash (**Postgres:** `prisma_contract.marker`; **Mongo:** `_prisma_migrations`). The DB is at a different contract version than the code thinks. Either run a migration forward, or — if the DB is correct and the marker is stale after a manual fix-up — run `db sign`. |
76
+ | `CONTRACT.MARKER_MISSING` | `db verify` (finding, exit 4), runtime startup (warning) | The DB has no marker yet. Run `prisma db init --db <url>` to baseline an empty database, `db update --db <url>` to apply the current contract directly, or `db sign --db <url>` if the schema already matches the contract. |
77
+
78
+ ## Decision — which path do you take?
79
+
80
+ | Situation | Path | Why |
81
+ |---|---|---|
82
+ | Local dev, schema in flux | `db update` | Fast, interactive, no migration files. |
83
+ | Shared branch with other developers | `migration plan` + `db migrate` | Replayable, reviewable, content-hashed. |
84
+ | Anything reaching production | `migration plan` + `db migrate` | Production must run a reviewed, hashed migration. |
85
+ | Adding a column that needs a backfill | `migration plan` (writes `placeholder`), edit `migration.ts`, self-emit, then `db migrate` | `db update` does not author data transforms; the formal path does. |
86
+ | Recovering from drift (DB diverged from contract) | `db sign` after manual fix, *or* `migration plan` if PN can plan the fix | Depends on which side is right. See *Recover from drift* below. |
87
+
88
+ ## Dev → ship transition (the `db` ref pattern)
89
+
90
+ Example — iterate locally with `db update`, then publish the first real migration:
91
+
92
+ ```bash
93
+ pnpm prisma db init --db $DATABASE_URL
94
+ pnpm prisma contract emit && pnpm prisma db update --db $DATABASE_URL
95
+ pnpm prisma contract emit && pnpm prisma migration plan --name add_feature
96
+ pnpm prisma db migrate --db $DATABASE_URL
97
+ pnpm prisma db verify --db $DATABASE_URL
98
+ ```
99
+
100
+ The `db` ref is a named pointer at `migrations/app/refs/db.json` — just `{ hash, invariants }`. It records which contract hash the project's dev database has been brought up to — the offline planner's stand-in for "where is my local DB?" without opening a connection at plan time. The contract it names resolves through the shared content-addressed store at `migrations/snapshots/<hex>/contract.json` by that hash, the same store every migration graph node resolves through.
101
+
102
+ **What `db init` / `db update` / `db sign` write.** When run against the project's default `--db` URL (no explicit `--db` flag), `db init` and `db update` implicitly advance the `db` ref: they write-if-absent the post-command contract IR into the snapshot store, then write the ref's pointer. Override the ref name with `--advance-ref <name>`. When you pass `--db <non-default-url>`, ref advancement is suppressed unless `--advance-ref` is explicit — reconciling a different database is not the same as checkpointing this project's dev state. `db sign` also advances the `db` ref after a successful signature, writing the signed contract into the snapshot store first; `--advance-ref <name>` overrides the name, and `--db` does **not** suppress it — sign never mutates the schema, and adoption is normally done against the real database via `--db`. The only opt-out is `--no-advance-ref`, which signs without writing any ref or snapshot — what a CI or deployment pipeline, or a dev checkout re-signing a production database, usually wants.
103
+
104
+ The on-disk layout is just the pointer:
105
+
106
+ ```text
107
+ migrations/app/refs/
108
+ └── db.json # { "hash": "<hex>", "invariants": [] }
109
+ ```
110
+
111
+ **First `migration plan` after dev iteration.** `migration plan` defaults `--from` to the `db` ref (and, when no `db` ref exists at all, falls back to planning from an empty database only while the migration graph is empty — the human output then adds a muted notice beneath the summary, `No db ref set — planning from an empty database. Run db init, db update, or db sign if a database already exists.`, and the JSON document carries `fromDefaulted: true`; over a non-empty graph there is no fallback: the command refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN`; see `references/migration-model.md` § *The trap*). When the on-disk migration graph is still **empty** and the `db` ref points at a non-null hash with a store entry (typical after one or more `db update` cycles), the planner emits **two** bundles instead of one:
112
+
113
+ 1. Baseline: `null → from-hash` (introduces `from-hash` as a graph node)
114
+ 2. Delta: `from-hash → current_contract`
115
+
116
+ Both land on disk in one invocation — expect two new directories in `git status`. `db migrate` then finds a path through the baseline and applies the delta. This closes the dev → ship trap where a single-bundle plan referenced a hash that was not yet a graph node and produced an unapplyable migration (`MIGRATION.PATH_UNREACHABLE` at apply time).
117
+
118
+ **The forgot-the-flag pitfall.** After the graph is **non-empty**, the default `db` ref may point **past the graph tip** (the ref advanced on every `db update` while you iterated, but you never committed migrations). The next implicit-default `migration plan` refuses with `MIGRATION.HASH_NOT_IN_GRAPH` and names reachable refs that point at graph nodes.
119
+
120
+ Recovery when you see `MIGRATION.HASH_NOT_IN_GRAPH` on plan:
121
+
122
+ ```bash
123
+ # Option A — plan from a graph node explicitly
124
+ pnpm prisma migration plan --from production --name my_change
125
+
126
+ # Option B — realign the db ref to a graph-node hash, then plan with the default
127
+ pnpm prisma migration ref set db <graph-node-hash>
128
+ pnpm prisma migration plan --name my_change
129
+ ```
130
+
131
+ If the `db` ref's pointer is itself missing and the hash isn't a graph node either (`MIGRATION.SNAPSHOT_MISSING`), create it with `migration ref set db <hash>` or advance it with `db update --advance-ref db`.
132
+
133
+ **After plain `db migrate`.** `db migrate` does not implicitly advance the `db` ref (production-shaped commands stay explicit). The live marker advances while the ref may lag. Refresh with `db update` (no-op on DB when already current) or `db migrate --advance-ref db` in the same invocation.
134
+
135
+ **When to switch paths.** Use `db update` while the schema is in flux on a solo dev database. Switch to `migration plan` + `db migrate` when the change needs a reviewable, replayable migration — typically before opening a PR or touching any shared environment. The `db` ref bridges the two: it captures dev iteration state on disk so the first formal plan knows where you left off.
136
+
137
+ **Graph-node rule (plan time).** Any hash used as a `from` end — explicit `--from`, default `db` ref, or ref name — must already be a node in the on-disk migration graph once the graph is non-empty. The auto-baseline two-bundle emission is the one exception: it applies only on an **empty** graph with a non-null ref-resolved `from` and an available store entry. If the ref's pointer is missing and the hash isn't a graph node either, plan refuses with `MIGRATION.SNAPSHOT_MISSING` instead.
138
+
139
+ **Apply-time complement.** `db migrate` reads the live marker before DDL. If the marker hash is not a graph node, the command refuses with `MIGRATION.MARKER_MISMATCH` — catching drift the offline planner cannot see. This is separate from `MIGRATION.MARKER_NOT_IN_HISTORY`, which fires later during the runner's graph walk when the marker is off the path being traversed. See `references/migration-review.md` for the full diagnostic catalog.
140
+
141
+ `db` is a **default ref name**, not a reserved one. The framework overwrites it on the next dev cycle; you may `migration ref set db <hash>` explicitly and accept that a subsequent `db update` replaces it when run against the default URL.
142
+
143
+ Canonical detail: [Migration System § Contract resolution through the snapshot store](https://github.com/prisma/orm/blob/main/docs/architecture%20docs/subsystems/7.%20Migration%20System.md#contract-resolution-through-the-snapshot-store), [§ `migration plan`](https://github.com/prisma/orm/blob/main/docs/architecture%20docs/subsystems/7.%20Migration%20System.md#migration-plan), [§ Recovery affordances](https://github.com/prisma/orm/blob/main/docs/architecture%20docs/subsystems/7.%20Migration%20System.md#recovery-affordances), [ADR 218 — Refs with paired contract snapshots and universal graph-node invariant](https://github.com/prisma/orm/blob/main/docs/architecture%20docs/adrs/ADR%20218%20-%20Refs%20with%20paired%20contract%20snapshots%20and%20universal%20graph-node%20invariant.md) (TML-2629, its paired-snapshot part superseded — see the ADR's Status note), and [ADR 240 — Contract snapshots live in a content-addressed store](https://github.com/prisma/orm/blob/main/docs/architecture%20docs/adrs/ADR%20240%20-%20Contract%20snapshots%20live%20in%20a%20content-addressed%20store.md).
144
+
145
+ ## Workflow — `db update` (quick path)
146
+
147
+ The concept: `db update` resolves the destination (`emitted contract`) against the live DB and applies the difference. Preview with `--dry-run`. Destructive ops need consent: interactively the command asks you to type the database name; with `--no-interactive` (CI) it reads `--confirm <database>` instead, and refuses with `MIGRATION.DESTRUCTIVE_CHANGES` if neither is given. `--yes` accepts prompt defaults and never grants this consent. The path excludes operations of the `data` class entirely — if the diff requires a data transform, `db update` fails with a planning error and you switch to `migration plan` to author the transform.
148
+
149
+ Run after a contract edit:
150
+
151
+ ```bash
152
+ pnpm prisma contract emit
153
+ # Postgres: --db postgresql://...
154
+ # Mongo: --db mongodb://... (dev scaffolds often need ?replicaSet=rs0)
155
+ pnpm prisma db update --db $DATABASE_URL --dry-run
156
+ pnpm prisma db update --db $DATABASE_URL
157
+ ```
158
+
159
+ `db update` already verifies schema and advances the marker on success — a follow-up `db verify` is redundant on the happy path. Use `db verify` only when you need a standalone diagnostic (see *Verify contract vs DB*).
160
+
161
+ Inspect the JSON output to drive the next move:
162
+
163
+ ```bash
164
+ pnpm prisma db update --db $DATABASE_URL --json
165
+ ```
166
+
167
+ The JSON contains `plan.operations[]` with each `operationClass`, plus (in apply mode) `execution.operationsExecuted` and the post-apply `marker.storageHash`. If the command failed because of destructive operations, the error envelope's `meta.destructiveOperations[]` lists exactly what would have been dropped.
168
+
169
+ ## Workflow — `migration plan` + `db migrate` (formal path)
170
+
171
+ The concept: `migration plan` writes a new migration package on disk. If the planner needed any data transforms, the package is *pending* — `migration.ts` holds `placeholder(...)` calls until you fill them in. `db migrate` runs every pending package in graph order — on Postgres inside one transaction for the whole run; on Mongo op by op with verify-gated marker advancement (see *Apply atomicity* above).
172
+
173
+ Plan a change:
174
+
175
+ ```bash
176
+ pnpm prisma contract emit
177
+ pnpm prisma migration plan --name <snake_slug>
178
+ ```
179
+
180
+ Read the result. The JSON shape exposes the queryable signals:
181
+
182
+ - `dir` — the path of the new package (e.g. `migrations/app/20260515T1200_add_user_email/`).
183
+ - `pendingPlaceholders` — `true` if `migration.ts` still contains `placeholder(...)` calls.
184
+ - `operations[].operationClass` — for spotting `destructive` and `data` ops.
185
+ - `preview.statements` — family-agnostic textual preview.
186
+
187
+ Inspect the package (the `<target>` positional is required — a directory name, hash or hash prefix, ref, or path):
188
+
189
+ ```bash
190
+ pnpm prisma migration show <dirName-or-migrationHash-prefix>
191
+ pnpm prisma migration show migrations/app/20260515T1200_add_user_email
192
+ ```
193
+
194
+ `migration show` displays a single migration package. To see the ordered list of migrations that would run — across all contract spaces — use `db migrate --show`:
195
+
196
+ ```bash
197
+ # Online: reads the live DB marker as the origin.
198
+ pnpm prisma db migrate --show --db $DATABASE_URL
199
+
200
+ # Offline: hypothetical path from any ref or hash.
201
+ pnpm prisma db migrate --show --from <hash-or-ref> --to <hash-or-ref>
202
+ ```
203
+
204
+ `db migrate --show` is read-only and never writes to the DB or the migration graph. Use it before applying to confirm the execution order.
205
+
206
+ Fill in any data transforms (see *Fill a placeholder*), self-emit if you edited `migration.ts`, then:
207
+
208
+ ```bash
209
+ pnpm prisma db migrate --db $DATABASE_URL
210
+ ```
211
+
212
+ `db migrate` runs without prompting — destructive-op confirmation lives on `db update`, not here. Review destructive ops in the plan output or in `migration show` *before* applying.
213
+
214
+ ## Workflow — Fill a placeholder
215
+
216
+ The concept: the planner can detect *that* a data transform is needed but not *what* it should do. It writes a typed scaffold and stops; you fill the transform, then self-emit.
217
+
218
+ ### Postgres
219
+
220
+ The planner can detect *that* a data transform is needed (e.g. backfilling a new `NOT NULL` column with no default) but not *what* it should do. You fill `check` and `run` closures with real query plans built against `endContract`.
221
+
222
+ The scaffold the planner emits looks like:
223
+
224
+ ```typescript
225
+ // migrations/app/20260515T1200_add_user_name/migration.ts
226
+ import { col, Migration, MigrationCLI, placeholder } from '@internal/postgres/migration';
227
+ import type { Contract as End } from '../../snapshots/93f07d1b…c9e1e5a2/contract';
228
+ import endContract from '../../snapshots/93f07d1b…c9e1e5a2/contract.json' with { type: 'json' };
229
+ import type { Contract as Start } from '../../snapshots/f62a4154…d07dddc/contract';
230
+ import startContract from '../../snapshots/f62a4154…d07dddc/contract.json' with { type: 'json' };
231
+
232
+ export default class M extends Migration<Start, End> {
233
+ override readonly startContractJson = startContract;
234
+ override readonly endContractJson = endContract;
235
+
236
+ override get operations() {
237
+ return [
238
+ this.addColumn({
239
+ schema: 'public',
240
+ table: 'user',
241
+ column: col('name', 'text', { codecRef: { codecId: 'pg/text@1' } }),
242
+ }),
243
+ this.dataTransform(endContract, 'backfill-user-name', {
244
+ check: () => placeholder('backfill-user-name:check'),
245
+ run: () => placeholder('backfill-user-name:run'),
246
+ }),
247
+ this.setNotNull({ schema: 'public', table: 'user', column: 'name' }),
248
+ ];
249
+ }
250
+ }
251
+
252
+ MigrationCLI.run(import.meta.url, M);
253
+ ```
254
+
255
+ (`examples/prisma-8-demo/migrations/app/20260810T1108_add_post_engagement_counters/migration.ts` is a committed rendered package to compare against.)
256
+
257
+ Replace both `placeholder(...)` calls with query-plan closures built from `endContract`. The `check` closure must return a **rowset query whose presence of any row signals "work remains"** — conventionally `<table>.select('id').where(<violation predicate>).limit(1)`. Scalar/aggregate shapes (`count(*)`, `bool_and(...)`) silently break the contract: the runner wraps `check` twice (`EXISTS(...)` for precheck, `NOT EXISTS(...)` for postcheck), and a query that always returns one row makes `EXISTS` always true and `NOT EXISTS` always false.
258
+
259
+ Build the query builder against `endContract` so the storage hashes line up — using a different contract reference raises `MIGRATION.DATA_TRANSFORM_CONTRACT_MISMATCH`. The cheapest way to get a typed SQL builder over the end contract is the façade itself: `postgres<End>({ contractJson: endContract })` connects lazily, so constructing it inside `migration.ts` opens no connection; its `sql` is the builder and its `contract` is the validated contract to hand to `this.dataTransform`. The filled-in shape is the rendered scaffold above with only the two `placeholder(...)` arrows replaced (the operation list, including the `this.setNotNull({...})` the planner rendered after the transform, stays as rendered):
260
+
261
+ ```typescript
262
+ import { col, Migration, MigrationCLI } from '@internal/postgres/migration';
263
+ import postgres from '@internal/postgres/runtime';
264
+ import type { Contract as End } from '../../snapshots/93f07d1b…c9e1e5a2/contract';
265
+ import endContract from '../../snapshots/93f07d1b…c9e1e5a2/contract.json' with { type: 'json' };
266
+ import type { Contract as Start } from '../../snapshots/f62a4154…d07dddc/contract';
267
+ import startContract from '../../snapshots/f62a4154…d07dddc/contract.json' with { type: 'json' };
268
+
269
+ const { sql: db, contract } = postgres<End>({ contractJson: endContract });
270
+
271
+ export default class M extends Migration<Start, End> {
272
+ override readonly startContractJson = startContract;
273
+ override readonly endContractJson = endContract;
274
+
275
+ override get operations() {
276
+ return [
277
+ this.addColumn({
278
+ schema: 'public',
279
+ table: 'user',
280
+ column: col('name', 'text', { codecRef: { codecId: 'pg/text@1' } }),
281
+ }),
282
+ this.dataTransform(contract, 'backfill-user-name', {
283
+ check: () => db.public.user.select('id').where((f, fns) => fns.eq(f.name, null)).limit(1),
284
+ run: () => db.public.user.update({ name: '' }).where((f, fns) => fns.eq(f.name, null)),
285
+ }),
286
+ this.setNotNull({ schema: 'public', table: 'user', column: 'name' }),
287
+ ];
288
+ }
289
+ }
290
+
291
+ MigrationCLI.run(import.meta.url, M);
292
+ ```
293
+
294
+ Self-emit:
295
+
296
+ ```bash
297
+ node migrations/app/20260515T1200_add_user_name/migration.ts
298
+ ```
299
+
300
+ Self-emit regenerates `ops.json` and recomputes `migrationHash` in `migration.json`. The next `db migrate` will see a consistent package.
301
+
302
+ ### Mongo
303
+
304
+ Mongo `dataTransform` operations are free factories taking `{ check, run }` objects whose `source` / `run` return Mongo query-plan shapes (often `RawAggregateCommand` / `RawUpdateManyCommand` from `@prisma/orm-mongo/query-ast/execution`). The planner may leave `placeholder(...)` inside those sources until you fill them. A rendered package binds its bookends through `startContractJson` / `endContractJson` exactly as on Postgres; a hand-authored `migration new` package may instead override `describe()` with the `from` / `to` hashes from its `migration.json`, as below. Everything comes from one import:
305
+
306
+ ```typescript
307
+ import { createIndex, dataTransform, Migration, MigrationCLI } from '@prisma/orm-mongo/target/migration';
308
+ import { RawAggregateCommand, RawUpdateManyCommand } from '@prisma/orm-mongo/query-ast/execution';
309
+
310
+ class M extends Migration {
311
+ override describe() {
312
+ return { from: '<hex>', to: '<hex>' };
313
+ }
314
+
315
+ override get operations() {
316
+ return [
317
+ createIndex('users', [{ field: 'name', direction: 1 }]),
318
+ dataTransform('lowercase-user-name', {
319
+ check: {
320
+ source: () => ({
321
+ collection: 'users',
322
+ command: new RawAggregateCommand('users', [
323
+ { $match: { name: { $regex: '[A-Z]' } } },
324
+ { $limit: 1 },
325
+ ]),
326
+ meta: { target: 'mongo', storageHash: '…', lane: 'mongo-pipeline', paramDescriptors: [] },
327
+ }),
328
+ },
329
+ run: () => ({
330
+ collection: 'users',
331
+ command: new RawUpdateManyCommand(
332
+ 'users',
333
+ { name: { $exists: true } },
334
+ [{ $set: { name: { $toLower: '$name' } } }],
335
+ ),
336
+ meta: { target: 'mongo', storageHash: '…', lane: 'mongo-raw', paramDescriptors: [] },
337
+ }),
338
+ }),
339
+ ];
340
+ }
341
+ }
342
+
343
+ export default M;
344
+ MigrationCLI.run(import.meta.url, M);
345
+ ```
346
+
347
+ Self-emit the same way: `node migrations/app/<dir>/migration.ts`.
348
+
349
+ ## Workflow — Author a migration by hand
350
+
351
+ The concept: the same `Migration` class shape lets you author operations directly when the planner has nothing to plan (a custom data fix, an extension install, a baseline). Even here you don't write the file from scratch — `migration new` renders an empty package for you, and you edit the `operations` getter inside it, then self-emit.
352
+
353
+ ```bash
354
+ pnpm prisma migration new --name <snake_slug>
355
+ ```
356
+
357
+ On Postgres the operations are **methods on the `Migration` base class**, each taking one options object (`this.addColumn({ schema, table, column })`); only helpers such as `col(...)` and `rawSql(...)` are imported, on the rendered `@internal/postgres/migration` line. On Mongo the operations are **free factories** imported from `@prisma/orm-mongo/target/migration`. The authoritative list for either target is the base class / module's declaration file in your `node_modules`.
358
+
359
+ **Postgres** operations (representative set, all `this.<name>({...})`):
360
+
361
+ - Tables: `createTable`, `dropTable`.
362
+ - Columns: `addColumn` (`column: col(name, nativeType, { codecRef })`), `dropColumn`, `alterColumnType`, `setNotNull`, `dropNotNull`, `setDefault`, `dropDefault`.
363
+ - Constraints: `addPrimaryKey`, `addForeignKey`, `addUnique`, `addCheckConstraint`, `renameCheckConstraint`, `dropCheckConstraint`, `dropConstraint`.
364
+ - Indexes: `createIndex`, `renameIndex`, `dropIndex`.
365
+ - Enums: `createNativeEnumType`, `addNativeEnumValue`, `dropNativeEnumType`.
366
+ - Row-level security: `enableRowLevelSecurity`, `disableRowLevelSecurity`, `createRlsPolicy`, `renameRlsPolicy`, `dropRlsPolicy`.
367
+ - Dependencies: `createSchema`, `installExtension`.
368
+ - Free helpers on the import line: `col`, `primaryKey`, `unique`, `foreignKey`, `checkExpression`, `lit`, `fn` (column and constraint descriptors), `createExtension`, and the raw escape hatch `rawSql({ id, label, operationClass, target, precheck, execute, postcheck, ... })`.
369
+ - Data transforms: `this.dataTransform(endContract, name, { check, run })`.
370
+
371
+ **Mongo** factories (from `@prisma/orm-mongo/target/migration`):
372
+
373
+ - Collections: `createCollection`, `dropCollection`, `validatedCollection`, `setValidation`.
374
+ - Indexes: `createIndex`, `dropIndex`.
375
+ - Collection options: `collMod`.
376
+ - Data transforms: `dataTransform(name, { check, run })` (free factory; `check`/`run` use Mongo query-plan shapes).
377
+
378
+ Self-emit (`node migrations/app/<dir>/migration.ts`) after each edit.
379
+
380
+ ## Workflow — Inspect the live schema
381
+
382
+ The concept: `db schema` is read-only and never writes files. It prints the live schema as a tree by default or as JSON with `--json`. Use it during planning and as part of verification.
383
+
384
+ ```bash
385
+ pnpm prisma db schema --db $DATABASE_URL
386
+ pnpm prisma db schema --db $DATABASE_URL --json > schema.json
387
+ ```
388
+
389
+ There is no built-in filter flag — pipe the JSON through `jq` (or your favourite JSON tool) if you only want one table.
390
+
391
+ ## Workflow — Verify contract vs DB (diagnostic)
392
+
393
+ The concept: `db verify` is a **standalone diagnostic** — not a routine step after `db update` or `db migrate` on the happy path (those commands already verify and advance the marker when they succeed). Reach for `db verify` when you suspect drift or need to prove the DB matches the contract:
394
+
395
+ - Following manual SQL or ad-hoc edits outside Prisma 8.
396
+ - When restoring a database from backup.
397
+ - If a `db migrate` fails or partially applies (especially on Mongo, where DDL is resumable rather than transaction-wrapped).
398
+ - When `CONTRACT.MARKER_MISMATCH` / `CONTRACT.MARKER_MISSING` surfaces at runtime or from another command.
399
+
400
+ Modes:
401
+
402
+ - Default — full verification (schema + marker).
403
+ - `--marker-only` — skip schema verification, only check the marker.
404
+ - `--schema-only` — skip marker verification, only check schema satisfies contract.
405
+ - `--strict` adds: schema elements not present in the contract are an error (default is "DB may have extras").
406
+
407
+ ```bash
408
+ pnpm prisma db verify --db $DATABASE_URL
409
+ ```
410
+
411
+ `db verify` exits `0` when everything matches, `4` when it ran and found something, and `2` only when it could not run. Findings ride the completed envelope as `error` diagnostics: `CONTRACT.MARKER_MISMATCH`, `CONTRACT.MARKER_MISSING`, `CONTRACT.TARGET_MISMATCH`, `CONTRACT.SCHEMA_VERIFICATION_FAILED` (with `meta.issues` naming the drifted paths).
412
+
413
+ ## Workflow — Re-sign the marker
414
+
415
+ The concept: `db sign` rewrites the marker to the current contract hash and moves the `db` ref to it (`--advance-ref <name>` overrides the ref name; `--db` does not suppress the ref write; `--no-advance-ref` skips it). Use after a manual repair where the DB is the source of truth and the marker is stale. `db sign` performs a schema-verify first and refuses to sign a DB whose schema disagrees with the contract — so a successful sign always means the schema matches and the marker is now correct.
416
+
417
+ ```bash
418
+ pnpm prisma db sign --db $DATABASE_URL
419
+ ```
420
+
421
+ ## Workflow — Recover from drift
422
+
423
+ The concept: drift means `db verify` reports the live DB schema doesn't match what the marker says it should be. Two valid moves, picked by which side is correct:
424
+
425
+ - **The contract is right; the DB is wrong** → run a migration. Either `db update` (quick path, dev DB only) or `migration plan` + `db migrate` (everywhere else).
426
+ - **The DB is right; the contract or marker is wrong** → edit the contract to match the DB (see `references/contract.md`), emit, then `db sign` to refresh the marker. The sign also moves the `db` ref to the signed hash; when the migration graph is non-empty and that hash is not a graph node, the next default `migration plan` refuses with `MIGRATION.HASH_NOT_IN_GRAPH` (see *The forgot-the-flag pitfall* above for the recovery).
427
+
428
+ The diagnostic that reveals which side is right:
429
+
430
+ ```bash
431
+ pnpm prisma db schema --db $DATABASE_URL --json
432
+ pnpm prisma db verify --db $DATABASE_URL --json
433
+ ```
434
+
435
+ Use `db verify` to confirm which side is wrong, then re-run it after either branch until it returns `ok` with no diagnostics.
436
+
437
+ ## Workflow — Recover from a partially-applied migration
438
+
439
+ The concept: on **Postgres**, the whole `db migrate` run is one transaction — a failure anywhere rolls back every migration the run had applied, and the marker stays where it was before the command. On **Mongo**, DDL is resumable with verify-gated marker advancement; diagnose with `db verify` / `db schema`, fix the failed package's `migration.ts`, self-emit, and re-run `db migrate`.
440
+
441
+ Failures that *can* leak partial state: Mongo DDL that partially applied before verify failed, and external side-effects (calls out to other systems from a `run` closure). On Postgres nothing runs outside the transaction — `rawSql(...)` steps are ordinary steps inside it and roll back with the rest.
442
+
443
+ Diagnose:
444
+
445
+ ```bash
446
+ pnpm prisma db verify --db $DATABASE_URL --json
447
+ pnpm prisma db schema --db $DATABASE_URL --json
448
+ ```
449
+
450
+ Fix and re-run `db migrate`:
451
+
452
+ ```bash
453
+ node migrations/app/<dir>/migration.ts
454
+ pnpm prisma db migrate --db $DATABASE_URL
455
+ ```
456
+
457
+ If the failure was an out-of-band side-effect that left external systems half-changed, repair those by hand before re-applying.
458
+
459
+ ## Workflow — Recover from `MIGRATION.HASH_MISMATCH`
460
+
461
+ The concept: `migrationHash` is content-addressed. A mismatch means `migration.json`'s stored hash disagrees with the hash recomputed from `ops.json` (and metadata). The cause is almost always: someone edited `migration.ts` and forgot to self-emit. The remediation is to self-emit the offending package.
462
+
463
+ ```bash
464
+ node migrations/app/<dir>/migration.ts
465
+ pnpm prisma db migrate --db $DATABASE_URL
466
+ ```
467
+
468
+ If self-emit itself fails (e.g. the contract has moved on and the operations no longer make sense against the migration's end contract), the package is stale. Either restore it from version control or delete it and re-plan with `migration plan`.
469
+
470
+ ## Workflow — Resolve a destructive-operation prompt (`db update` only)
471
+
472
+ The concept: when `db update` would drop columns or tables, it stops and asks before applying. The prompt is `db update`-specific — `db migrate` does *not* prompt and runs whatever the migration package contains, so review the plan or call `migration show` before `db migrate`.
473
+
474
+ When `db update` reports destructive operations interactively, the warning lists them. The prompt is:
475
+
476
+ > Apply destructive changes? This cannot be undone.
477
+
478
+ Routing:
479
+
480
+ - Answer yes if the data is no longer needed.
481
+ - Answer no, then either:
482
+ - Re-shape the migration via `migration plan` and hand-edit `migration.ts` to preserve the data (e.g. copy-to-new-column, then drop), or
483
+ - Skip the destructive operation by reverting the contract change.
484
+
485
+ Interactively, consent is typing the database name back (the prompt names it). In non-interactive contexts (CI, `--no-interactive`), the destructive-op response is returned as `MIGRATION.DESTRUCTIVE_CHANGES` — `meta.destructiveOperations[]` lists what would have been dropped. Re-run with `--confirm <database>` to grant consent (`--yes` does not), or address each operation individually.
486
+
487
+ ## Common Pitfalls
488
+
489
+ 1. **Using `db update` against shared or production databases.** Never. The change leaves no migration history. Use `migration plan` + `db migrate`.
490
+ 2. **Skipping a data transform.** Leaving `placeholder(...)` in `migration.ts` makes the next `db migrate` throw `MIGRATION.UNFILLED_PLACEHOLDER`. Fill every placeholder slot and self-emit.
491
+ 3. **Editing `ops.json` directly.** It's the canonical artifact, not the authoring source. Edit `migration.ts`, then self-emit.
492
+ 4. **Forgetting to self-emit after editing `migration.ts`.** The next `db migrate` either uses the stale `ops.json` (if you only added comments) or fails with `MIGRATION.HASH_MISMATCH` (if you changed operations). Always self-emit.
493
+ 5. **Routine `db verify` after a successful `db update` or `db migrate`.** Redundant on the happy path — reserve `db verify` for drift diagnosis (manual edits, restore, failed `db migrate`).
494
+ 6. **Aggregate `check` closure in Postgres `this.dataTransform`.** Returning `count(*)` or `bool_and(...)` breaks the precheck/postcheck contract — both sides resolve to constants. Use a rowset shape: `select('id').where(<violation>).limit(1)`.
495
+ 7. **Two contract references in one migration.** Building a query plan against a different contract than the one passed to `this.dataTransform(endContract, ...)` raises `MIGRATION.DATA_TRANSFORM_CONTRACT_MISMATCH`. Always import `endContract` once at module scope and use the same reference.
496
+ 11. **Calling Postgres operations as free functions.** `addColumn('public', 'user', {...})` does not exist as an import; the operations are `this.addColumn({ schema, table, column })` and friends on the `Migration` base class, with `col(...)` building the column. Only `col`, `rawSql`, `placeholder`, `Migration`, and `MigrationCLI` are imported.
497
+ 8. **Renaming and expecting the planner to detect it (Postgres).** Prisma 8 has no in-contract rename hint today; the planner emits a destructive drop+add. Hand-edit `migration.ts` to rewrite the destructive op as a `rawSql({ ... })` that issues `ALTER TABLE ... RENAME COLUMN ...` (or use the two-migration keep / backfill / drop pattern), then self-emit. See `references/contract.md` § *Edit a field — rename*.
498
+ 9. **Planning with no `db` ref and no `--from` in a project that already has migrations.** The origin falls through to the empty database, which would make the plan a full-create migration; `migration plan` refuses with `MIGRATION.PLAN_ORIGIN_UNKNOWN` rather than writing it. Pick the exit that matches your intent — the error lists them, and `references/migration-model.md` § *The trap* explains which to choose.
499
+ 10. **Hand-authoring `migration.ts` from a blank file, or rewriting the rendered import line.** Migration files are framework-rendered — let `prisma migration plan` (or `migration new`) render the package, then edit only the holes the framework leaves for you. On Postgres leave the rendered `@internal/postgres/migration` (or `@internal/sqlite/migration`) import path alone; on Mongo leave `@prisma/orm-mongo/target/migration` as rendered. Add symbols to the existing import line rather than introducing new import paths.
500
+
501
+ ## What Prisma 8 doesn't do yet
502
+
503
+ - **Runtime-apply migrations.** Prisma 8 doesn't apply pending migrations from your app's startup code (the "Drizzle pattern" for serverless / edge). Workaround: run `prisma db migrate` from your deploy pipeline before the app starts. If you need runtime-apply built-in, file a feature request via the `references/feedback.md` skill.
504
+ - **Seeds-as-first-class.** Prisma 8 doesn't ship a `prisma db seed` equivalent. Workaround: write a TypeScript script that imports your `db` instance and runs your setup queries; invoke it from `package.json`'s scripts. If you need first-class seeding, file a feature request via the `references/feedback.md` skill.
505
+ - **Migration squashing.** Prisma 8 doesn't squash older migrations into a baseline. They accumulate; for very large histories, manual baseline-and-truncate is the path. If you need built-in squashing, file a feature request via the `references/feedback.md` skill.
506
+ - **In-contract rename hints.** The planner cannot detect that a field rename is a rename rather than a drop+add. Workaround: hand-edit `migration.ts` to issue a `RENAME COLUMN` via `rawSql(...)`, or use a keep / backfill / drop pattern across two migrations. If you need a contract-level rename hint, file a feature request via the `references/feedback.md` skill.
507
+
508
+ ## Graph and history commands
509
+
510
+ After planning or applying, you can inspect the migration graph offline:
511
+
512
+ - `pnpm prisma migration list` — enumerate all on-disk migrations, rendered as a graph tree. Supports `--legend` (print the glyph key), `--ascii` (pipe-safe glyphs), and `--json`.
513
+ - `pnpm prisma migration log --db $DATABASE_URL` — flat chronological table of applied migrations, read from the live DB. Supports `--ascii` and `--json`.
514
+
515
+ For the full graph topology: `pnpm prisma migration graph` (also supports `--legend`, `--ascii`, `--dot`, `--json`).
516
+
517
+ ## `@@control` and DDL scope
518
+
519
+ Objects whose `@@control` policy excludes them from Prisma 8's managed surface are omitted from planned DDL. The four policies are: `managed` (Prisma plans and applies DDL), `tolerated` (object may exist, no DDL emitted), `external` (object is expected to exist, no DDL), `observed` (Prisma reads but never writes). Declare `@@control(managed|tolerated|external|observed)` in your schema; see `references/contract.md` and [`packages/2-sql/2-authoring/contract-psl/README.md`](https://github.com/prisma/orm/blob/main/packages/2-sql/2-authoring/contract-psl/README.md) for authoring syntax.
520
+
521
+ ## Telemetry
522
+
523
+ The CLI collects anonymous usage data by default. To opt out, set `PRISMA_DISABLE_TELEMETRY=1` or `DO_NOT_TRACK=1` in your environment. See [`docs/Telemetry.md`](https://github.com/prisma/orm/blob/main/docs/Telemetry.md) for the full opt-out reference.
524
+
525
+ ## Checklist
526
+
527
+ - [ ] Contract emitted (`contract.json` + `contract.d.ts` current).
528
+ - [ ] Chose the right path: `db update` (local dev) vs `migration plan` + `db migrate` (anything shared).
529
+ - [ ] For `migration plan`: confirmed the output's `from:` line names the intended origin — not `(baseline)` over an existing graph (`references/migration-model.md`).
530
+ - [ ] For `migration plan`: ran `migration show <dir>` to review before `db migrate`.
531
+ - [ ] Filled every `placeholder(...)` in `migration.ts` (if any), built against `endContract`.
532
+ - [ ] `check` closures are rowset queries, not scalar aggregates.
533
+ - [ ] Self-emitted (`node migrations/app/<dir>/migration.ts`) after editing the TS.
534
+ - [ ] Ran `db migrate` (or `db update`) and saw it complete.
535
+ - [ ] Used `db verify` only when diagnosing drift — not as a routine post-apply step.
536
+ - [ ] Did NOT use `db update` against a shared or production database.
537
+ - [ ] Did NOT edit `ops.json` directly.
538
+ - [ ] Did NOT skip a destructive-op prompt without inspecting `meta.destructiveOperations[]`; granted consent with the database name (or `--confirm <database>`), not `--yes`.