Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,12 @@ The command replaces the example contract from step 2. For a database with a `us

namespace public {
model User {
id Int @id(map: "user_pkey") @default(autoincrement())
email String @unique(map: "user_email_key")
id Int @id(map: "user_pkey") @default(autoincrement())
email String @unique(map: "user_email_key")
name String?
role String @default("member")
role String @default("member")
age Int?
createdAt Timestamptz @default(now()) @map("created_at")
createdAt TimestamptzString @default(now()) @map("created_at")
posts Post[]

@@check(expression: "(age >= 0)", map: "user_age_check")
Expand Down Expand Up @@ -136,7 +136,7 @@ namespace public {
}
```

Keep the first line, because `contract emit` reads only `.prisma` files that start with it. `namespace public` holds the models of the tables in the PostgreSQL schema `public`. Where Prisma ORM 7 wrote `DateTime @db.Timestamptz`, the contract writes `Timestamptz`, and `String @db.VarChar(200)` becomes `VarChar(200)`. In the policy block, `roles = [public]` is the PostgreSQL role `PUBLIC`, not the schema.
Keep the first line, because `contract emit` reads only `.prisma` files that start with it. `namespace public` holds the models of the tables in the PostgreSQL schema `public`. Where Prisma ORM 7 wrote `DateTime @db.Timestamptz`, the contract writes `TimestamptzString`, and `String @db.VarChar(200)` becomes `VarChar(200)`. In the policy block, `roles = [public]` is the PostgreSQL role `PUBLIC`, not the schema.

`contract infer` reads these parts of the database and writes each one into the contract:

Expand All @@ -153,11 +153,11 @@ Review the file before you go on. You can rename models, and you can remove the

A table without a model stays in your database, and later migrations leave it alone. Do not remove the model of a table that has row-level security policies, though. If you do, `db sign` in step 6 fails, because it finds policies that the contract does not declare.

### Date and time columns on Node.js 24 and older
### Date and time columns

`contract infer` gives a `timestamptz` column the type `Timestamptz`, and a `timestamp` column the type `Timestamp`. Prisma ORM returns the values of these columns as `Temporal` objects. `Temporal` is the new date and time API of JavaScript. Node.js 26 has it built in. Node.js 24 and older do not, and there the first query that reads such a column fails with `RUNTIME.TEMPORAL_UNAVAILABLE`.
`contract infer` gives a `timestamptz` column the type `TimestamptzString`, a `timestamp` column `TimestampString`, a `date` column `DateString`, and a `time` column `TimeString`. Prisma ORM returns the values of these columns as the text PostgreSQL prints, such as `2026-09-30 07:36:38.60182+02`, so your app needs no `Temporal`.

On Node.js 24 or older, install the `temporal-polyfill` package:
To get `Temporal` objects instead, the new date and time API of JavaScript, change the type of each such field in the contract: `TimestamptzString` becomes `Timestamptz`, `TimestampString` becomes `Timestamp`, `DateString` becomes `Date`, and `TimeString` becomes `Time`. The column in the database stays as it is. Node.js 26 has `Temporal` built in. Node.js 24 and older do not, and there the first query that reads such a column fails with `RUNTIME.TEMPORAL_UNAVAILABLE`. On Node.js 24 or older, install the `temporal-polyfill` package:

```npm
npm install temporal-polyfill
Expand All @@ -169,8 +169,6 @@ Then add this line at the top of `src/prisma/db.ts`:
import "temporal-polyfill/global";
```

If you would rather not add the package, change the type of each such field in the contract: `Timestamptz` becomes `TimestamptzString`, and `Timestamp` becomes `TimestampString`. The field then holds the text that PostgreSQL returns, such as `2026-09-30 07:36:38.60182+02`, and needs no `Temporal`. The column in the database stays as it is.

### Tables in other PostgreSQL schemas

`contract infer` reads only the PostgreSQL schema named `public`. It skips tables in any other schema and prints no message about them.
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/docs/(index)/prisma-orm/from-scratch.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ npm install @prisma/orm-postgres dotenv
npm install --save-dev prisma tsx typescript
```

`@prisma/orm-postgres` is the library your code imports, and `prisma` is the command-line tool. `dotenv` loads `.env`, `tsx` runs `index.ts` without a build step, and `typescript` 5.9 or newer is a peer dependency of `@prisma/orm-postgres`. So is `temporal-polyfill`, which npm installs for you; with Yarn, add it yourself. The two Prisma packages have different version numbers (for example, `prisma` 8.0.0-rc.20 and `@prisma/orm-postgres` 8.0.0-rc.14); that is normal, and any two `latest` versions work together.
`@prisma/orm-postgres` is the library your code imports, and `prisma` is the command-line tool. `dotenv` loads `.env`, `tsx` runs `index.ts` without a build step, and `typescript` 5.9 or newer is a peer dependency of `@prisma/orm-postgres`. So is `temporal-polyfill`, which npm installs for you; with Yarn, add it yourself. The two Prisma packages have different version numbers (for example, `prisma` 8.0.0-rc.21 and `@prisma/orm-postgres` 8.0.0-rc.16); that is normal, and any two `latest` versions work together.

## 2. Create the config file and `.env`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ installed
├─ dotenv
├─ prisma@latest (dev)
├─ @types/node (dev)
└─ @prisma/cli-engine@0.6.2 (dev)
└─ @prisma/cli-engine@0.6.3 (dev)

✔ Done. Open prisma-8.md to get started.
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ installed
├─ dotenv
├─ prisma@latest (dev)
├─ @types/node (dev)
└─ @prisma/cli-engine@0.6.2 (dev)
└─ @prisma/cli-engine@0.6.3 (dev)

✔ Done. Open prisma-8.md to get started.
```
Expand Down
4 changes: 3 additions & 1 deletion apps/docs/content/docs/cli/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export default definePrismaConfig({
});
```

`prisma7Schema` takes one schema file, or a directory of `.prisma` files as Prisma ORM 7 reads it. It reads every `.prisma` file it is given, so these files do not need the `// use prisma-8` first line. `contract emit` writes `contract.json` and `contract.d.ts` into the directory that holds the schema, here `prisma/`, unless you set `output`. Prisma ORM 7 keeps owning the database and its migrations, and you run its commands as `prisma7`, the Prisma ORM 7 CLI that [`orm init --from-prisma7-schema`](/cli/orm-init#on-a-prisma-orm-7-project) installs next to Prisma ORM 8.
`prisma7Schema` takes one schema file, or a directory of `.prisma` files as Prisma ORM 7 reads it. A `DateTime` field, and a field with `@db.Timestamp`, `@db.Timestamptz`, `@db.Date`, or `@db.Time`, reads and writes strings such as `"2026-09-14 10:00:00.123"`, the text PostgreSQL prints, not `Temporal` values, so your application needs no `Temporal`. A `DateTime` value is in UTC, as Prisma ORM 7 writes it. To get `Temporal` values, write a Prisma ORM 8 contract with `npx prisma contract print --output prisma/contract.prisma` and change the types there. It reads every `.prisma` file it is given, so these files do not need the `// use prisma-8` first line. `contract emit` writes `contract.json` and `contract.d.ts` into the directory that holds the schema, here `prisma/`, unless you set `output`. Prisma ORM 7 keeps owning the database and its migrations, and you run its commands as `prisma7`, the Prisma ORM 7 CLI that [`orm init --from-prisma7-schema`](/cli/orm-init#on-a-prisma-orm-7-project) installs next to Prisma ORM 8.

Once the config is in place, run `npx prisma contract emit` and then [`npx prisma db sign`](/cli/db-sign). `db sign` checks that the database matches the contract and then records that in the database, without changing your tables. Run both commands again after each Prisma ORM 7 migration, whether you ran `npx prisma7 migrate dev` or `npx prisma7 migrate deploy`, so that the record names the new contract.

Expand All @@ -148,6 +148,8 @@ export default definePrismaConfig({

The schema file does not need the `// use prisma-8` first line. Run `npx prisma contract emit` and then [`npx prisma db sign`](/cli/db-sign), which checks that the database Prisma ORM 6 built matches the contract.

`prisma6Schema` reads each field as the BSON type Prisma ORM 6 stores. A plain `Int` and an `Int @db.Long` are a `number` in your code, written as a BSON long, and a stored value with a fraction fails to read with `RUNTIME.DECODE_FAILED`. A `Bytes @db.ObjectId` field reads as a 24-digit hex string and takes a hex string or an `ObjectId`, not a `Buffer`. Every native type Prisma ORM 6 accepts on MongoDB is read, except `DateTime @db.Timestamp`.

`contract emit` fails on any part of the schema that Prisma ORM 8 cannot represent exactly, with an error code that starts with `PSL.PRISMA6_MONGO_`. The [error reference](/orm/reference/error-reference) lists each code and what to change.

## Write your own contract source
Expand Down
14 changes: 12 additions & 2 deletions apps/docs/content/docs/cli/contract-emit.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,25 @@ The command emits:
- `contract.json`, the canonical machine-readable contract
- `contract.d.ts`, the generated TypeScript contract declarations

Do not edit these files by hand. Re-run `contract emit` after changing the contract source or extension pack list. The first emit after you upgrade from a release before `8.0.0-rc.12` reorders the entries in `contract.d.ts` to follow the order in `contract.json`, which needs no change to your code. The first emit after you upgrade from a release before `8.0.0-rc.13` renames two keys in `contract.json`: each generated default under `execution.mutations.defaults` names its target as `entry` and `field` instead of `table` and `column`. The client refuses a contract that has the old keys, so run `contract emit` after you upgrade. `contract emit` does not rewrite the contracts stored under `migrations/`, such as the snapshots in `migrations/snapshots/`. To rename the keys in them, download the [`rename-execution-ref-keys` script](https://github.com/prisma/orm/blob/v8.0.0-rc.14/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.12-to-8.0.0-rc.13/scripts/execution-ref-entry-field/rename-execution-ref-keys.ts) into your project root and run it there:
Do not edit these files by hand. Re-run `contract emit` after changing the contract source or extension pack list. The first emit after you upgrade from a release before `8.0.0-rc.12` reorders the entries in `contract.d.ts` to follow the order in `contract.json`, which needs no change to your code. The first emit after you upgrade from a release before `8.0.0-rc.13` renames two keys in `contract.json`: each generated default under `execution.mutations.defaults` names its target as `entry` and `field` instead of `table` and `column`. The client refuses a contract that has the old keys, so run `contract emit` after you upgrade. `contract emit` does not rewrite the contracts stored under `migrations/`, such as the snapshots in `migrations/snapshots/`. To rename the keys in them, download the [`rename-execution-ref-keys` script](https://github.com/prisma/orm/blob/v8.0.0-rc.15/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.12-to-8.0.0-rc.13/scripts/execution-ref-entry-field/rename-execution-ref-keys.ts) into your project root and run it there:

```bash title="Terminal"
curl -O https://raw.githubusercontent.com/prisma/orm/v8.0.0-rc.14/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.12-to-8.0.0-rc.13/scripts/execution-ref-entry-field/rename-execution-ref-keys.ts
curl -O https://raw.githubusercontent.com/prisma/orm/v8.0.0-rc.15/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.12-to-8.0.0-rc.13/scripts/execution-ref-entry-field/rename-execution-ref-keys.ts
npx tsx rename-execution-ref-keys.ts
```

The script renames `table` to `entry` and `column` to `field` in each `ref` under `execution.mutations.defaults`, in every `.json` and `.d.ts` file under a `migrations/` folder. It leaves each `executionHash` as it is, and a second run changes nothing. Pass `--check` to list the files it would change without writing them.

Since `8.0.0-rc.15`, each SQL column in `contract.json` stores its data type id, such as `"dataType": "pg/text"`, in place of `nativeType`, and the client refuses a contract in the old format. When you upgrade from a release before `8.0.0-rc.15`, upgrade every extension that ships migrations, such as pgvector and PostGIS, in the same step. Then, before the first emit, run the [`data-type-in-contract` script](https://github.com/prisma/orm/blob/v8.0.0-rc.15/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.14-to-8.0.0-rc.15/scripts/data-type-in-contract/data-type-in-contract.ts) in your project root, and sign every database with [`db sign`](/cli/db-sign):

```bash title="Terminal"
curl -O https://raw.githubusercontent.com/prisma/orm/v8.0.0-rc.15/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.14-to-8.0.0-rc.15/scripts/data-type-in-contract/data-type-in-contract.ts
node data-type-in-contract.ts
npx prisma db sign --db "$DATABASE_URL"
```

The script needs Node 24 or later. It rewrites every contract, snapshot, migration, ref, `migration.ts`, and `contract.d.ts` in the project, and every storage hash changes once. Until a database is signed, `db migrate` refuses with `MIGRATION.MARKER_MISMATCH`. Commit your work before you run it, so you can review its changes.

When the contract source cannot be read, the command fails with `CONTRACT.SOURCE_LOAD_FAILED` and prints each finding, meaning each problem it found in the source, with the file and line where it knows them. In `--json` output, the findings are the entries of the `envelope.diagnostics` array in the final `result` event, next to `envelope.error`. Each entry has a `code`, a `summary`, and, where known, `where.path` and `where.line`. If an entry's `code` is `CONTRACT.SOURCE_DIAGNOSTIC`, the code of the specific problem, such as `PSL_NO_OPTED_IN_SCHEMA_FILES`, is in its `meta.code`.

A warning in the contract source, such as `PSL_DEPRECATED_SCALAR_NAME` for a MongoDB scalar type name that is deprecated, does not stop the command. It is reported as a diagnostic whose `severity` is `warn`, and the command still writes both files. In `--json` output, the warning is an entry of `envelope.diagnostics` in the final `result` event, with `code` set to `CONTRACT.SOURCE_DIAGNOSTIC` and the warning's own code in `meta.code`.
Expand Down
4 changes: 4 additions & 0 deletions apps/docs/content/docs/cli/contract-infer.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ The file starts with `// use prisma-8`, because `contract emit` reads only `.pri

Every column default is written in a form `contract emit` accepts, so you can emit the file without editing it. [Default values](/orm/contract-authoring/psl-syntax#default-values) shows those forms. A list column that allows `NULL` is written `Type[]?`, and a list column that is `NOT NULL` is written `Type[]`.

Date and time columns are written as text types, so your application reads and writes them as strings and needs no `Temporal`: a `timestamp(3)` column is written `TimestampString(3)`, `timestamptz(3)` is `TimestamptzString(3)`, `date` is `DateString`, and `time(3)` is `TimeString(3)`. A `timestamp` value reads as `"2026-09-14 10:00:00.123"`. To get `Temporal` values instead, change the types to `Timestamp(3)`, `Timestamptz(3)`, `Date`, and `Time(3)` in the inferred file. A `bytea` default is written as the base64 text the `Bytes` type stores, such as `@default("aGVsbG8=")`.

A contract inferred before `8.0.0-rc.15` keeps its types until you run `contract infer` again. When you do, the date and time fields and any `bytea` default change, and so does the storage hash: emit the contract, update the code that used `Temporal` values for these fields, then run `prisma db sign` for a database you keep with `db update`, or create an empty migration with [`migration new`](/cli/migration-new) and apply it when you use migrations.

If you keep an inferred contract in version control, running `contract infer` again after an upgrade can write the same database differently, so review the diff before you commit it.

The command stops at `contract.prisma`. Follow it with the emit and sign steps:
Expand Down
Loading
Loading