Skip to main content
Prisma Documentation Docs

Search documentation

Type to search this documentation.

On this pageOverview

contract.json and contract.d.ts (/docs/orm/contract-authoring/the-contract-artifact)

For the complete Prisma documentation index, see llms.txt. A markdown version of any docs page is available by appending .md to its URL.

contract.json and contract.d.ts are the two files every other part of Prisma ORM reads. Here is what is inside them.

Location: ORM > Contract authoring > contract.json and contract.d.ts

Your contract is a single file that describes your data and how it is stored. It replaces the schema.prisma of Prisma ORM 7 and is either src/prisma/contract.prisma in Prisma Schema Language (PSL) or src/prisma/contract.ts in TypeScript. npx prisma contract emit reads that file and writes two files beside it. In the table below, db is your client, the object you run queries on. npx prisma orm init creates the contract source, src/prisma/db.ts, and .env.example for you. In Prisma ORM 7 you edited schema.prisma and the tooling read the same file, but now you edit the contract and the tooling reads the two files it produces.

File Contents Read by
contract.json The machine-readable contract: models, how they are stored, which database features they need, and the hashes db, prisma db sign, prisma db verify, and prisma migration plan
contract.d.ts TypeScript declarations derived from the contract The query APIs and your application code, for typed models and results

prisma db sign writes the current contract's hashes into the database, so later commands can tell which contract that database was built for. Both files are generated, so do not edit them: change the PSL or TypeScript source and run npx prisma contract emit again. contract.d.ts starts with a comment saying it is generated and must not be edited, and contract.json carries the same notice in a _generated entry. To write the two files to another directory, see prisma contract emit.

The everyday loop on a project:

  1. Edit contract.prisma or contract.ts.
  2. Run npx prisma contract emit.
  3. Create the migration with npx prisma migration plan, read it, then apply it with npx prisma db migrate.
  4. Check the database against the contract with npx prisma db verify in CI or in your deploy step.

npx prisma db verify reports whether the database has a record and whether it matches. You almost never sign a database yourself:

The same source always produces the same two files

Section titled “The same source always produces the same two files”

Run npx prisma contract emit on the same source on any machine and you get the same two files, byte for byte. That holds only if your contract source does not read the environment, the clock, or random values, and the TypeScript authoring page lists the rules.

npx prisma contract emit computes a hash over each part of the contract, and you never compute or compare them yourself. storageHash covers the storage layout: tables, columns, primary keys, uniques, indexes, foreign keys, and the allowed values of each enum. profileHash covers which database the contract targets. The hashes are how Prisma ORM connects the contract to a live database: npx prisma db sign checks that the database satisfies the contract, then records storageHash and profileHash in the database. npx prisma db verify compares the contract you hold against that record and against the live schema, and fails when they disagree. To fix a mismatch, apply the pending migration, or run npx prisma db sign when the database already matches the contract.

The contract keeps your application's view of the data separate from the way the database stores it. The domain section describes models, fields, and relations, while the storage section describes tables, columns, keys, and indexes. On MongoDB it describes collections and indexes instead. Each model's own storage block maps each field to its column. Everything is grouped by namespace, and on PostgreSQL the namespace is the schema, which is public unless you put the models in a namespace block in your PSL source.

An abridged contract.json for a User and Post schema:

src/prisma/contract.json (abridged)
{
  "schemaVersion": "1",
  "targetFamily": "sql",
  "target": "postgres",
  "profileHash": "…",
  "roots": {
    "Post": { "model": "Post", "namespace": "public" },
    "User": { "model": "User", "namespace": "public" }
  },
  "domain": {
    "namespaces": {
      "public": {
        "models": {
          "User": {
            "fields": {
              "email": { "nullable": false, "type": { "codecId": "pg/text@1", "kind": "scalar" } },
              "id": { "nullable": false, "type": { "codecId": "pg/uuid@1", "kind": "scalar" } }
            },
            "storage": {
              "fields": { "email": { "column": "email" }, "id": { "column": "id" } },
              "namespaceId": "public",
              "table": "User"
            }
          }
        }
      }
    }
  },
  "storage": {
    "namespaces": {
      "public": {
        "entries": {
          "table": {
            "User": {
              "columns": {
                "email": { "codecId": "pg/text@1", "nativeType": "text", "nullable": false },
                "id": { "codecId": "pg/uuid@1", "nativeType": "uuid", "nullable": false }
              },
              "primaryKey": { "columns": ["id"] }
            }
          }
        }
      }
    },
    "storageHash": "…"
  },
  "capabilities": { "postgres": { "returning": true } }
}

The sections, top to bottom:

  • schemaVersion, targetFamily, target: the contract format version, whether the database is SQL or MongoDB, and which database this contract targets.
  • roots: one entry per table that stores a model. The key is the name of that table, so for a model User mapped to a table users the key is users. The value names the model. You can query the model's data in two ways. The SQL query builder, db.sql, reaches the table by its table name, and the ORM API, db.orm, reaches the model by its model name. In this example both names are User, because the model sets no @@map, so the calls are db.sql.public.User and db.orm.public.User. For a model User mapped to a table users, they are db.sql.public.users and db.orm.public.User. The ORM reference covers both.
  • domain and storage: your application's view, then the database's view. Each scalar field in domain records whether it is nullable and its codecId. nativeType is the column type in the database. codecId names how Prisma ORM reads and writes the value, the PostgreSQL type plus a version. storage holds the tables with their columns, keys, indexes, constraints, and enum values. prisma db verify compares it to the live database.
  • capabilities: which database features this contract can use. npx prisma contract emit collects them from the adapter for your database and from the packages listed in extensions: [...] in prisma.config.ts, the config file prisma orm init writes. The query APIs check them before building a query that needs one. See supported database features and extension types.

The declarations file gives the type system the same information. It exports:

  • Contract, the type the client is built from. db.ts imports it.
  • One type per hash, such as StorageHash and ProfileHash. Each one carries the hash of that part of the contract.
  • Input and output types for each type block in your contract.
src/prisma/contract.d.ts (excerpt)
export type StorageHash =
  StorageHashBase<'fac9b49833c04e1ea5da153f6f7c2444520bbbc24cc5bcf7e21a80b199ca412b'>;

You never write these types yourself. Both files come from the one npx prisma contract emit run, so they only drift when someone commits one and not the other. The CI check below catches that.

db is built from both files: contract.json as the value, contract.d.ts as the type. prisma orm init writes src/prisma/db.ts for you.

src/prisma/db.ts
import "dotenv/config";
import postgres from "@prisma/orm-postgres/runtime";
import type { Contract } from "./contract.d";
import contractJson from "./contract.json" with { type: "json" };

export const db = postgres<Contract>({
  contractJson,
  url: process.env['DATABASE_URL']!,
});

The connection string comes from the DATABASE_URL environment variable: prisma orm init writes .env.example, and you put your DATABASE_URL in .env. Keep the .d in the import path: it names contract.d.ts, so the import still finds the generated type when you author the contract in TypeScript and a contract.ts sits beside it. The tsconfig.json settings the JSON import needs are on the transactions and runtime page. Before its first query, db reads the record in the database of which contract it matches and compares it with the contract's hashes. If they do not match, it logs a warning whose code is CONTRACT.MARKER_MISMATCH and runs the query anyway. If there is no record at all, because nothing has signed the database yet, it logs a warning whose code is CONTRACT.MARKER_MISSING and again runs the query. On MongoDB the client is mongo<Contract>(...) from @prisma/orm-mongo/runtime, described under mongo(options).

When CONTRACT.MARKER_MISMATCH shows up in production, apply the pending migration, or run npx prisma db sign when the database already matches the contract. The client warns by default, and you can set verifyMarker to false to skip the check. It cannot be made to fail, so run prisma db verify when you need a check that fails.

Commit contract.json and contract.d.ts alongside the source: they hold structure only, no data and no credentials. Committing them lets teammates, CI, and deploys read the contract without running npx prisma contract emit first. Run npx prisma contract emit after every source change so the two files never trail the source; in a Vite project, the Vite plugin does that whenever the contract or prisma.config.ts changes while the dev server runs. A CI job can check this in two lines:

Bash
npx prisma contract emit
git diff --exit-code src/prisma

Projects created with npm create prisma@latest include the Prisma ORM skills for your coding agent. In an existing project, run npx prisma skills sync to add them. The prisma-8 skill covers the contract, so ask your agent to:

  • "Explain the difference between contract.json and contract.d.ts in this project."
  • "Run prisma contract emit and show me what changed in contract.json."
  • Author in PSL: Write the Prisma ORM contract in the Prisma schema language you already know, plus the Prisma ORM 8 additions.
  • Author in TypeScript: Define the Prisma ORM contract with a typed builder in TypeScript instead of a schema file. Same models, same contract.json and contract.d.ts, no separate language.
  • Editor support: What the Prisma VS Code extension does for a Prisma ORM contract, and what to do when it stops accepting the file.
  • Supported database features: The contract records which database features your packages support, so Prisma ORM can reject an unsupported one early with a clear error.
  • The data contract: The data contract is the one description of your data model and how it is stored. Prisma ORM types your queries, plans your migrations, and checks your database against it.
Suggest an edit

Propose a replacement for this page. The site team reviews it before applying any changes.

Export
Documentation menu