@prisma/orm-mongo 8.0.0-rc.9-dev.12 → 8.0.0-rc.9-dev.13

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/orm-mongo",
3
- "version": "8.0.0-rc.9-dev.12",
3
+ "version": "8.0.0-rc.9-dev.13",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -10,16 +10,16 @@
10
10
  "skills"
11
11
  ],
12
12
  "dependencies": {
13
- "@prisma/orm-family-mongo": "8.0.0-rc.9-dev.12",
14
- "@prisma/orm-framework": "8.0.0-rc.9-dev.12",
15
- "@prisma/orm-target-mongo": "8.0.0-rc.9-dev.12",
16
- "@prisma/orm-toolchain": "8.0.0-rc.9-dev.12",
13
+ "@prisma/orm-family-mongo": "8.0.0-rc.9-dev.13",
14
+ "@prisma/orm-framework": "8.0.0-rc.9-dev.13",
15
+ "@prisma/orm-target-mongo": "8.0.0-rc.9-dev.13",
16
+ "@prisma/orm-toolchain": "8.0.0-rc.9-dev.13",
17
17
  "pathe": "^2.0.3"
18
18
  },
19
19
  "devDependencies": {
20
- "@internal/mongo": "8.0.0-rc.9-dev.12",
21
- "@repo/tsconfig": "8.0.0-rc.9-dev.12",
22
- "@repo/tsdown": "8.0.0-rc.9-dev.12",
20
+ "@internal/mongo": "8.0.0-rc.9-dev.13",
21
+ "@repo/tsconfig": "8.0.0-rc.9-dev.13",
22
+ "@repo/tsdown": "8.0.0-rc.9-dev.13",
23
23
  "tsdown": "0.22.14",
24
24
  "typescript": "5.9.3"
25
25
  },
@@ -15,7 +15,7 @@ description: >-
15
15
  ORM 7 or earlier (schema.prisma + @prisma/client).
16
16
  metadata:
17
17
  library: '@prisma/orm-mongo'
18
- library_version: '8.0.0-rc.9-dev.12'
18
+ library_version: '8.0.0-rc.9-dev.13'
19
19
  version: '2026-09-11'
20
20
  ---
21
21
 
@@ -60,7 +60,7 @@ Open the reference whose triggers match the task. If more than one matches, open
60
60
  | Adopt / set up / first steps | [`references/quickstart.md`](references/quickstart.md) | new project, existing database, "what can I do with Prisma 8", "where do I start", "just ran createprisma", `npx create-prisma`, first steps, first query, `prisma orm init` greenfield setup, `contract infer` + `db sign` brownfield adoption, connect-write-read first arc, day-to-day commands (`contract emit`, `db init`, `db update`, `migration plan`, `db migrate`, `db schema`, `db verify`), flags `--target` / `--authoring` / `--schema-path` / `--probe-db` / `--output` |
61
61
  | Edit the data contract | [`references/contract.md`](references/contract.md) | schema, models, fields, attributes, relations, indexes, enums, value objects (composite types), type aliases, namespaces (Postgres schemas), cross-contract foreign keys (cross-space FK), polymorphic types (`@@discriminator` / `@@base`), extension namespaces (`pgvector.Vector(...)`, `postgis.Geometry(...)`), `prisma.config.ts` / `definePrismaConfig` / `ormConfig`, `prisma contract emit`, PSL, `contract.prisma`, `contract.ts`, `contract.json`, `contract.d.ts`, `@internal/postgres/config`, `@internal/postgres/contract-builder`, `@internal/mongo/config`, `extensions:`, pgvector, postgis, paradedb, Temporal / `temporal-polyfill` / `RUNTIME.TEMPORAL_UNAVAILABLE`, `@@control`, control policy (managed / tolerated / external / observed), soft delete, validations, callbacks |
62
62
  | Author migrations | [`references/migrations.md`](references/migrations.md) | `db update` vs `migration plan`, `db migrate`, `migration new`, `migration show`, `db update --dry-run`, `db verify`, `db sign`, data migration, `dataTransform`, placeholder sentinels in framework-rendered `migration.ts`, `MIGRATION.HASH_MISMATCH`, `MIGRATION.UNFILLED_PLACEHOLDER`, `MIGRATION.DESTRUCTIVE_CHANGES` / `--confirm <database>`, schema drift |
63
- | Migration graph, refs, plan origin | [`references/migration-model.md`](references/migration-model.md) | migration graph, refs, `migration ref set` / `list` / `delete`, the `db` ref, `--advance-ref`, `migration plan --from`, `from: (baseline)` in plan output, greenfield / from-scratch plan, baseline, first migration before deploy (Composer / CD-managed databases), chaining migrations, retrofitting migrations onto an existing database, `MIGRATION.HASH_NOT_IN_GRAPH`, `MIGRATION.PATH_UNREACHABLE` at plan/chain time |
63
+ | Migration graph, refs, plan origin | [`references/migration-model.md`](references/migration-model.md) | migration graph, refs, `migration ref set` / `list` / `delete`, the `db` ref, `--advance-ref`, `--no-advance-ref`, `migration plan --from`, `from: (baseline)` in plan output, greenfield / from-scratch plan, baseline, first migration before deploy (Composer / CD-managed databases), chaining migrations, retrofitting migrations onto an existing database, `MIGRATION.HASH_NOT_IN_GRAPH`, `MIGRATION.PATH_UNREACHABLE` at plan/chain time |
64
64
  | Review migrations on deploy | [`references/migration-review.md`](references/migration-review.md) | "what migrations are going to run", "what runs on deploy / merge", merge conflict, diamond convergence, concurrent migrations, migration status, ref management for CI, staging / production environment refs, `MIGRATION.MARKER_NOT_IN_HISTORY`, `MIGRATION.MISSING_INVARIANTS`, `MIGRATION.AMBIGUOUS_TARGET`, `db migrate --show` |
65
65
  | Write queries | [`references/queries.md`](references/queries.md) | query, where, select, project, orderBy, limit, offset, take, skip, include, lookup, first, all, count, aggregate, groupBy, create, update, delete, upsert, returning, transaction, `db.orm`, `db.sql`, `runtime.query(plan)` vs `runtime.execute(plan)`, `db.prepare` / prepared statements, streaming / `for await`, many-to-many `include` and nested `connect`, `and` / `or` / `not` from `@prisma/orm-postgres/orm-client`, `db.query.from(...)` (Mongo pipeline), namespace-aware accessors, `.all()` Thenable, single-use iterators (`RUNTIME.ITERATOR_CONSUMED`), target-declared aggregate types (`count`, integer `sum`, and integer `avg` are `number`; `count` and integer `sum` throw outside ±(2^53 − 1) rather than round, while `avg` is a fraction already and carries no guard; `countBigInt` / `sumBigInt` / `avgDecimal` are the lossless forms, `avgDecimal` on PostgreSQL only), drizzle-style, kysely-style. Naming types (§ *Naming model and result types*): "type of my model", "return type of a query", `ResultType`, `Scalars`, `Shape`, `models` / `Models` namespace in `contract.d.ts`, `Models.public_User`, Prisma 7 `Prisma.User` / `GetPayload` / `UserGetPayload` equivalents. Postgres/SQLite specifics: [`references/queries-postgres.md`](references/queries-postgres.md); Mongo specifics: [`references/queries-mongo.md`](references/queries-mongo.md) |
66
66
  | Wire the runtime | [`references/runtime.md`](references/runtime.md) | `db.ts`, `postgres<Contract>(...)` / `sqlite<Contract>(...)` / `mongo<Contract>(...)` façades, middleware composition (lints, budgets, cache via `@prisma/orm-extension-middleware-cache`, custom `afterQuery` middleware, `@prisma/orm-postgres/family-runtime`), `DATABASE_URL`, `.env`, connection pool / `poolOptions`, dev vs prod config, transactions, read replicas, multi-database, script won't exit / hangs, `db.close` / `pool.end`, `await using` / `[Symbol.asyncDispose]` |
@@ -91,7 +91,7 @@ The single source of truth: read the envelope, find the row by `code`, follow th
91
91
  | `MIGRATION.INVALID_DEFAULT_EXPORT` | Loading `migration.ts` | Use `export default class extends Migration<Start, End> { ... }` (or a factory returning `{ operations, targetId, destination }`). See `references/migrations.md`. |
92
92
  | `MIGRATION.DATA_TRANSFORM_CONTRACT_MISMATCH` | Building a data-transform query plan | Pass the same `endContract` reference to both `this.dataTransform(endContract, …)` and the query-builder context. |
93
93
  | `MIGRATION.HASH_MISMATCH` | Any read of a migration package (`plan`, `list`, `db migrate`) | `ops.json` / `migration.json` were edited without self-emitting. Run `node migrations/app/<dir>/migration.ts` to re-emit. |
94
- | `CONTRACT.MARKER_MISSING` | `db verify` (`error` diagnostic, exit 4), runtime startup (warning) | DB has no marker yet. Run `prisma db init --db <url>` (baseline empty DB), `db update --db <url>` (apply contract directly), or `db sign` if the schema already matches. |
94
+ | `CONTRACT.MARKER_MISSING` | `db verify` (`error` diagnostic, exit 4), runtime startup (warning) | DB has no marker yet. Run `prisma db init --db <url>` (baseline empty DB), `db update --db <url>` (apply contract directly), or `db sign --db <url>` if the schema already matches the contract. |
95
95
  | `CONTRACT.MARKER_MISMATCH` | `db verify` (exit 4), runtime startup (warning) | Marker disagrees with contract hash (`meta.expected` / `meta.actual`). Either migrate forward (`db migrate` / `db update`), or — if the DB is correct after a manual fix-up — `db sign`. See `references/migrations.md`. |
96
96
  | `CONTRACT.TARGET_MISMATCH` | `db verify`, runtime startup | Contract target ≠ config target; align them (see `meta.expected` / `meta.actual`). |
97
97
  | `CONTRACT.SCHEMA_VERIFICATION_FAILED` | `db verify`, `db sign` (both exit 4 with the finding) | Live schema does not satisfy the contract; `meta.issues` lists the drifted paths per `meta.space`. Run `db update` to reconcile, or adjust the contract. |
@@ -116,10 +116,10 @@ If the envelope's `code` is not in this table, follow the envelope's `fix` field
116
116
 
117
117
  ## Common Pitfalls
118
118
 
119
- 1. **Reading only `summary`, not the rest of the envelope.** `code`, `severity`, `why`, `fix`, `meta`/`details`, and (for CLI errors) `where` are all load-bearing. The agent routes on `code`; the user sees `summary`.
119
+ 1. **Reading only `summary`, not the rest of the envelope.** `code`, `severity`, `why`, `fix`, `meta`/`details`, and (for CLI errors) `where` all carry information the recovery depends on. The agent routes on `code`; the user sees `summary`.
120
120
  2. **Ignoring `severity`.** `migration status` emits warn-level diagnostics and **exits 0**. An agent that only checks exit code misses every concurrent-migration warning.
121
121
  3. **Stopping at `code` on `MIGRATION.RUNNER_FAILED`.** That envelope is a wrapper — the detail lives in `why` and `meta`.
122
- 4. **Treating drift as something to silence with `db sign`.** `db sign` writes the marker from the current contract hash, but it requires schema verification to pass first. Run `db verify` before reaching for `db sign`.
122
+ 4. **Treating drift as something to silence with `db sign`.** `db sign` writes the marker from the current contract hash and, by default, advances the `db` ref to it (`--no-advance-ref` skips the ref), but it requires schema verification to pass first. Run `db verify` before reaching for `db sign`.
123
123
  5. **Re-running `db migrate` after a partial failure without inspecting state.** `db schema --db <url>` shows the live shape; `migration status --db <url> --json` shows where the marker actually is.
124
124
 
125
125
  ## What Prisma 8 doesn't do yet
@@ -55,6 +55,7 @@ pnpm prisma migration ref delete <name>
55
55
  | Command | Ref advancement |
56
56
  |---|---|
57
57
  | `db init` / `db update` (default URL) | Implicitly advance `db` (override the name with `--advance-ref <name>`; suppressed whenever `--db` is passed without `--advance-ref`, regardless of the URL — even `--db $DATABASE_URL` pointing at the default database) |
58
+ | `db sign` | Advances `db` after a successful signature (override the name with `--advance-ref <name>`; `--no-advance-ref` skips it, writing no ref and no snapshot); an existing ref is overwritten and the previous hash is reported in the human output (the JSON `advancedRef` carries name and hash only). `--db` does **not** suppress it, unlike init/update: sign never mutates the schema, and adoption is normally done via `--db` |
58
59
  | `db migrate --advance-ref <name>` | The **only** apply-time advancement |
59
60
  | plain `db migrate` | **Never advances anything** — deliberate: deploy and CI applies must not infer dev intent |
60
61
  | `migration plan` | Never advances anything — chaining discipline is yours |
@@ -66,7 +67,7 @@ pnpm prisma migration ref delete <name>
66
67
 
67
68
  1. Explicit `--from <ref-name | hash | hash-prefix | migration-dir | migration-dir^ | ./path | @empty>` — `@empty` names the empty database deliberately. The reserved forms `@db` and `@contract` exist in the shared ref grammar but do not resolve here: `migration plan` is offline, so `@db` (the live marker) has nothing to read, and `@contract` needs a contract hash the plan resolver does not pass. Use them with `db migrate --show` / `migration status`, not with `plan`.
68
69
  2. No `--from` → the `db` ref (`migrations/app/refs/db.json`).
69
- 3. No `db` ref → **greenfield: the plan starts from the empty database.**
70
+ 3. No `db` ref → **greenfield: the plan starts from the empty database.** On an empty graph the human output 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`, so this case is distinguishable from an explicit `--from @empty`.
70
71
 
71
72
  It is **offline** — it never consults a database, never reads a marker (which is why `--from @db` is not an option here). Whatever the refs on disk say is what it believes. The destination defaults to the emitted `contract.json` (`--to` overrides).
72
73
 
@@ -78,7 +79,7 @@ The human output names the resolved origin on its `from:` line. **`from: (baseli
78
79
 
79
80
  **A plan whose origin is the empty contract while migrations already exist on disk is almost always a mistake.** A full-create migration cannot do what you meant: a database that has the prior migrations applied refuses it (`MIGRATION.PATH_UNREACHABLE` — no path from its marker to the new plan's destination), and running its create statements against any populated schema fails outright. The CLI refuses this at plan time: when origin resolution falls all the way through (no `--from`, no `db` ref) and migrations exist, `migration plan` stops with `MIGRATION.PLAN_ORIGIN_UNKNOWN` instead of writing the package — the error's suggestions are the three exits below; do not reflexively take the `--from @empty` one, pick by intent.
80
81
 
81
- How the fall-through happens: a project that never runs `db init` / `db update` (the deploy-first path below) never acquires a `db` ref, so *every* default plan resolves to the empty origin. Running the dev loop with an explicit `--db` has the same effect: `db init` / `db update` with that flag never advance the ref, whatever URL it carries. The first time that is correct (it is the baseline; an empty migration graph plans silently); every later time it is the trap the refusal catches.
82
+ How the fall-through happens: a project that never runs `db init` / `db update` / `db sign` (the deploy-first path below) never acquires a `db` ref, so *every* default plan resolves to the empty origin. Running the dev loop with an explicit `--db` has the same effect: `db init` / `db update` with that flag never advance the ref, whatever URL it carries (`db sign` is the exception — it advances the ref with or without `--db`). The first time that is correct (it is the baseline; an empty migration graph plans with only the muted notice); every later time it is the trap the refusal catches.
82
83
 
83
84
  **Recognize a from-empty plan** that was produced anyway (an explicit `--from @empty`, or an older CLI without the refusal), at either layer:
84
85
 
@@ -131,14 +132,14 @@ The concept: a database that predates Prisma 8 enters the system by describing i
131
132
  pnpm prisma contract infer --db "$DATABASE_URL" --output src/prisma/contract.prisma
132
133
  # review and re-author, then:
133
134
  pnpm prisma contract emit
134
- pnpm prisma db sign
135
+ pnpm prisma db sign --db "$DATABASE_URL" # advances the db ref even with --db
135
136
  ```
136
137
 
137
- After adoption the graph is still empty. Before the next schema change ships, author the baseline (deploy-first loop above) or start the dev loop otherwise the first real plan lands in the trap.
138
+ By default `db sign` sets the `db` ref to the signed contract's hash and stores its snapshot, so the next `migration plan` chains from the adopted schema (`--advance-ref <name>` writes another ref instead, and `--no-advance-ref` writes none; after either, set the `db` ref yourself with `migration ref set db <hash>` or pass `--from` on the next plan): the graph is still empty at that point, so the plan auto-emits the baseline `null → signed-hash`, plus a delta `signed-hash → contract` once the contract has moved on from the signed one. No baseline is written at sign time. If the graph is already non-empty and the signed hash is not a graph node, the next plan refuses with `MIGRATION.HASH_NOT_IN_GRAPH`, exactly as after `db update`.
138
139
 
139
140
  ## Workflow — retrofit a database that has no on-disk migrations
140
141
 
141
- The concept: the database exists and its marker is accurate (hash **M**) — it was built by `db update` in another checkout, by a deploy pipeline, or adopted via `db sign` but the migration graph doesn't reach M. The goal is to **make the graph reach the marker's hash**: once a baseline `null → M` exists, applying against the marked database is clean by construction — the runner starts at the marker, so the baseline never executes; only real deltas past M run.
142
+ The concept: the database exists and its marker is accurate (hash **M**) — it was built by `db update` or signed with `db sign` in another checkout, or built by a deploy pipeline but the migration graph doesn't reach M. (A database adopted with `db sign` in *this* checkout already has its ref set; retrofit is for the case where the ref was never set here.) The goal is to **make the graph reach the marker's hash**: once a baseline `null → M` exists, applying against the marked database is clean by construction — the runner starts at the marker, so the baseline never executes; only real deltas past M run.
142
143
 
143
144
  - **It's your dev database.** Run `db update` (default URL; no-op on the DB when the contract already matches) — it advances the `db` ref and stores the contract snapshot. The next `migration plan` auto-emits the baseline plus your delta. This is just the dev loop's dev → ship transition.
144
145
  - **It's a deployed database you must not touch.** Build the baseline offline, at the deployed contract state:
@@ -151,8 +152,8 @@ The concept: the database exists and its marker is accurate (hash **M**) — it
151
152
 
152
153
  ## Common Pitfalls
153
154
 
154
- 1. **Assuming `migration plan` chains from the newest migration on disk.** It never does. The origin is `--from`, else the `db` ref, else empty. If neither exists, you get a from-scratch plan with no warning.
155
- 2. **Expecting `migration plan` or plain `db migrate` to keep the `db` ref current.** Neither touches refs. Only `db init` / `db update` advance implicitly, and only `--advance-ref` advances at apply time.
155
+ 1. **Assuming `migration plan` chains from the newest migration on disk.** It never does. The origin is `--from`, else the `db` ref, else empty. If neither exists, you get a from-scratch plan; on an empty graph the only warning is the muted `No db ref set` notice.
156
+ 2. **Expecting `migration plan` or plain `db migrate` to keep the `db` ref current.** Neither touches refs. Only `db init` / `db update` / `db sign` advance implicitly, and only `--advance-ref` advances at apply time.
156
157
  3. **Expecting a deploy to update refs.** Deploys write the database's marker; the files under `migrations/app/refs/` only change when you change them.
157
158
  4. **Reading `from: (baseline)` as informational.** Over a non-empty migrations directory it is the trap announcing itself. Stop and pick an exit before applying or committing.
158
159
  5. **`migration ref set` with a hash no on-disk migration produces.** A ref target must be the `to` hash of an on-disk migration bundle. A hash outside the graph is refused (`MIGRATION.HASH_NOT_IN_GRAPH`); a from-only graph node is refused with `MIGRATION.REF_SET_BUNDLE_NOT_FOUND`, whose fix text points at fixtures and is unhelpful here. Either way: plan the edge whose `to` is the hash first (baseline or delta), then set the ref.
@@ -169,6 +170,6 @@ The concept: the database exists and its marker is accurate (hash **M**) — it
169
170
  - [ ] Read the plan output's `from:` line and confirmed it names that origin — not `(baseline)` over an existing graph.
170
171
  - [ ] In a deploy-first project: baseline authored and committed before the first deploy; every later plan chained via the `db` ref or `--from`.
171
172
  - [ ] After each plan in a loop where nothing advances refs: advanced the `db` ref (`migration ref set db <to-hash>`) or resolved to pass `--from` next time.
172
- - [ ] For a marked database with no on-disk migrations: made the graph reach the marker's hash (auto-baseline via `db update`, or an offline baseline plan) before planning deltas.
173
+ - [ ] For a marked database with no on-disk migrations: made the graph reach the marker's hash (auto-baseline via `db update` or `db sign`, or an offline baseline plan) before planning deltas.
173
174
  - [ ] Did NOT expect plain `db migrate`, `migration plan`, or a deploy to advance any ref.
174
175
  - [ ] Did NOT apply or commit a `from: (baseline)` plan without confirming the empty origin was the intent.
@@ -142,7 +142,7 @@ pnpm prisma migration ref delete production
142
142
 
143
143
  `migration ref set` writes a file at `migrations/app/refs/<name>.json` carrying the hash and any required invariants. Refs are commit-friendly artifacts — keep them in git; the team agrees on what `production` points at the same way they agree on what `main` is. The hash being set must be the `to` of an on-disk migration, or the command refuses — see `references/migration-model.md` for the refusal codes.
144
144
 
145
- Two ref roles, one mechanism: environment refs like `production` are the contract CD will migrate that environment to (a forward promise), while the `db` ref is a checkpoint of where the project's dev database was last brought to — written by `db init` / `db update`, consumed by `migration plan` as its default origin. `references/migration-model.md` covers the `db` ref, advancement rules, and plan-origin resolution.
145
+ Two ref roles, one mechanism: environment refs like `production` are the contract CD will migrate that environment to (a forward promise), while the `db` ref is a checkpoint of where the project's dev database was last brought to — written by `db init` / `db update` on the default URL and by `db sign` by default (`--advance-ref <name>` targets another ref, `--no-advance-ref` skips the write), consumed by `migration plan` as its default origin. `references/migration-model.md` covers the `db` ref, advancement rules, and plan-origin resolution.
146
146
 
147
147
  ## Workflow — apply a migration against an environment
148
148
 
@@ -73,7 +73,7 @@ Treat the rendered import lines as framework-managed on both targets:
73
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
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
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, or `db update --db <url>` to apply the current contract directly. |
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
77
 
78
78
  ## Decision — which path do you take?
79
79
 
@@ -99,7 +99,7 @@ pnpm prisma db verify --db $DATABASE_URL
99
99
 
100
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
101
 
102
- **What `db init` / `db update` write.** When run against the project's default `--db` URL (no explicit `--db` flag), both commands 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.
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
103
 
104
104
  The on-disk layout is just the pointer:
105
105
 
@@ -108,7 +108,7 @@ migrations/app/refs/
108
108
  └── db.json # { "hash": "<hex>", "invariants": [] }
109
109
  ```
110
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 with no warning — over a non-empty graph that fallback is almost always a mistake; 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:
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
112
 
113
113
  1. Baseline: `null → from-hash` (introduces `from-hash` as a graph node)
114
114
  2. Delta: `from-hash → current_contract`
@@ -412,7 +412,7 @@ pnpm prisma db verify --db $DATABASE_URL
412
412
 
413
413
  ## Workflow — Re-sign the marker
414
414
 
415
- The concept: `db sign` rewrites the marker to the current contract hash. 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.
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
416
 
417
417
  ```bash
418
418
  pnpm prisma db sign --db $DATABASE_URL
@@ -423,7 +423,7 @@ pnpm prisma db sign --db $DATABASE_URL
423
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
424
 
425
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.
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
427
 
428
428
  The diagnostic that reveals which side is right:
429
429
 
@@ -219,7 +219,7 @@ Then run the snippet from *Your first arc* above against the `User` model. When
219
219
 
220
220
  ## Workflow — Brownfield-DB (existing database, no contract)
221
221
 
222
- The concept: against an existing database with no PN contract, `contract infer` walks the live schema (tables, columns, indexes — including expression and partial ones — constraints, and RLS enablement + policies) and writes a PSL contract that describes it. Where authoring would generate a CHECK constraint the database does not carry (the element-non-null check on a list column), infer emits `@noCheck(elementNotNull)` on that field, so the contract declares exactly what the database enforces. The reverse gap is closed too: a hand-written CHECK constraint the database enforces that authoring would never have generated comes back as `@@check(expression: <reprint>, map: "<name>")`, so it is a declared object from the first pull instead of an invisible extra a later destructive plan could drop. That inferred check warns (`PN_EXACT_NAME_BODY_COMPARISON`) the next time you run `contract emit` — expected, not a defect: the warning fires on any `map:` body regardless of who wrote it, and the comparison stays sound because both sides are Postgres's own reprint. The result is a *starting point*, not the final contract — review and clean it up, then `db sign` to record the current contract hash as the marker (instead of letting `db init` try to recreate the schema from scratch).
222
+ The concept: against an existing database with no PN contract, `contract infer` walks the live schema (tables, columns, indexes — including expression and partial ones — constraints, and RLS enablement + policies) and writes a PSL contract that describes it. Where authoring would generate a CHECK constraint the database does not carry (the element-non-null check on a list column), infer emits `@noCheck(elementNotNull)` on that field, so the contract declares exactly what the database enforces. The reverse gap is closed too: a hand-written CHECK constraint the database enforces that authoring would never have generated comes back as `@@check(expression: <reprint>, map: "<name>")`, so it is a declared object from the first pull instead of an invisible extra a later destructive plan could drop. That inferred check warns (`PN_EXACT_NAME_BODY_COMPARISON`) the next time you run `contract emit` — expected, not a defect: the warning fires on any `map:` body regardless of who wrote it, and the comparison stays sound because both sides are Postgres's own reprint. The result is a *starting point*, not the final contract — review and clean it up, then `db sign` to record the current contract hash as the marker (instead of letting `db init` try to recreate the schema from scratch). By default `db sign` also sets the `db` ref and stores the contract snapshot, so the next `migration plan` chains from the adopted schema — even when the database is named with `--db`. `--advance-ref <name>` writes another ref instead and `--no-advance-ref` writes none; in either case the next plan needs `--from` or a `db` ref you set yourself.
223
223
 
224
224
  ```bash
225
225
  mkdir my-app && cd my-app
@@ -247,7 +247,7 @@ Then re-emit and sign:
247
247
 
248
248
  ```bash
249
249
  pnpm prisma contract emit
250
- pnpm prisma db sign
250
+ pnpm prisma db sign # writes the marker and sets the db ref
251
251
  pnpm prisma db verify # exit 0 immediately after a pull; exit 4 with findings if the DB drifts later
252
252
  ```
253
253
 
@@ -309,9 +309,9 @@ This skill is intentionally body-only; `prisma orm init --help`, `contract infer
309
309
  - [ ] **First-touch orientation:** read `prisma.config.ts`, the contract source, `db.ts`, and `.env` before proposing anything — didn't assume what the scaffold tool / teammate left in place.
310
310
  - [ ] **Greenfield path:** ran `prisma orm init` from the project directory — no positional project-name argument.
311
311
  - [ ] **All paths (application projects):** the project ended up in the canonical `src/prisma/contract.{prisma,ts}` + `src/prisma/db.ts` + `migrations/app/` layout (what `init` scaffolds by default). An extension or aggregate-root package keeps its own `src/contract.{prisma,ts}` + `migrations/<timestamp>_<slug>/` layout — do not relocate it.
312
- - [ ] **Brownfield path:** ran `contract infer --db "$DATABASE_URL" --output src/prisma/contract.prisma`, reviewed the result, then `contract emit` + `db sign`.
312
+ - [ ] **Brownfield path:** ran `contract infer --db "$DATABASE_URL" --output src/prisma/contract.prisma`, reviewed the result, then `contract emit` + `db sign` (which by default also sets the `db` ref, so the next `migration plan` chains from the adopted schema; not with `--no-advance-ref` or `--advance-ref <name>`).
313
313
  - [ ] Set `DATABASE_URL` in `.env` and confirmed the value is reachable.
314
- - [ ] Initialised the DB (`db init` greenfield / first-touch orientation) or signed the marker (`db sign` brownfield).
314
+ - [ ] Initialised the DB (`db init` greenfield / first-touch orientation) or signed the marker (`db sign` brownfield — by default sets the `db` ref too, with or without `--db`).
315
315
  - [ ] Did NOT hand-edit `contract.json` or `contract.d.ts`.
316
316
  - [ ] Did NOT set `DATABASE_URL` in `prisma.config.ts`.
317
317
  - [ ] Confirmed the user understands what the *next* skill is for their workflow (typically `references/queries.md` for more queries, then `references/contract.md` when they're ready to extend the schema).
@@ -35,7 +35,7 @@ This skill covers the **runtime entry point** — `db.ts` — and how to compose
35
35
 
36
36
  ## Workflow — Basic `db.ts`
37
37
 
38
- The concept: `db.ts` is the seam between the emitted contract artefacts (target-shaped) and the runtime that executes queries against them. Three imports are load-bearing — the runtime factory, the `Contract` type (so the static query surfaces are typed), and the JSON artefact (so the runtime validates the structure at construct time).
38
+ The concept: `db.ts` is the seam between the emitted contract artefacts (target-shaped) and the runtime that executes queries against them. Three imports are required — the runtime factory, the `Contract` type (so the static query surfaces are typed), and the JSON artefact (so the runtime validates the structure at construct time).
39
39
 
40
40
  `init` scaffolds something like this (for `--target postgres`):
41
41
 
@@ -55,7 +55,7 @@ export const db = postgres<Contract>({
55
55
 
56
56
  Three things to know:
57
57
 
58
- - **`<Contract>` type parameter is load-bearing.** Without it, the static surfaces collapse to a generic shape and you lose autocomplete on model names. Always import `Contract` from the emitted `./contract.d.ts`.
58
+ - **`<Contract>` type parameter is required.** Without it, the static surfaces collapse to a generic shape and you lose autocomplete on model names. Always import `Contract` from the emitted `./contract.d.ts`.
59
59
  - **`with { type: 'json' }` is required.** Node's ESM JSON-import-attribute spec. Without it, the import errors.
60
60
  - **`url` is optional at construct time.** If `DATABASE_URL` is not set when `db.ts` loads, the factory still returns a client; you can call `await db.connect({ url })` later. The factory throws lazily — only when a runtime is actually needed.
61
61
 
@@ -146,7 +146,7 @@ interface ClientFacade {
146
146
 
147
147
  This is the surface that lets a short-lived script (`tsx my-script.ts`) release facade-owned connection resources and exit cleanly. Without it, a `pg.Pool` (or analogous keep-alive in SQLite / Mongo) keeps Node's event loop alive and the script hangs after its last query prints.
148
148
 
149
- If your extension exposes a facade in the same shape (e.g. you publish your own `postgresServerless()` or `someDriver()` factory that returns the same client object), add the equivalent surface. Three load-bearing properties:
149
+ If your extension exposes a facade in the same shape (e.g. you publish your own `postgresServerless()` or `someDriver()` factory that returns the same client object), add the equivalent surface. Three properties the surface must have:
150
150
 
151
151
  1. **Ownership rule.** `close()` releases only the resources the facade *itself* constructed. A `{ url }` (or similar opaque-string) binding means the facade opened the connection — facade owns it, `close()` disposes it. A `{ pool }` / `{ client }` / `{ mongoClient }` (caller-supplied opaque-handle) binding means the caller owns it — `close()` leaves it untouched. The facade must capture this ownership decision at construction time and remember it.
152
152