Prisma ORM 8 is here.Read the docs

contract.json and contract.d.ts

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

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 it is 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. Now you edit the contract and the tooling reads the two files it produces.

FileContentsRead by
contract.jsonThe machine-readable contract: models, how they are stored, which database features they need, and the hashesdb, prisma db sign, prisma db verify, and prisma migration plan
contract.d.tsTypeScript declarations derived from the contractThe 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. 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

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.

The content hashes

npx prisma contract emit computes a hash over each part of the contract. 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.

Inside contract.json

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. 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. On PostgreSQL the namespace is the schema. It 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. The ORM reference covers both ways of reaching it, db.sql.public.user by table name and db.orm.public.User by model name.
  • 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.

Inside contract.d.ts

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<'9f49f8f9e51a9cc016f1ec2098ebae9406521a3cc2cf00207adc795078333d8b'>;

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.

How the application consumes the artifacts

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. Put your DATABASE_URL in .env. Keep the .d in the import path. Delete the .d and the import stops resolving. 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. Set verifyMarker to false to skip the check. It cannot be made to fail. Run prisma db verify when you need a check that fails.

Version control

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. A CI job can check this in two lines:

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

Prompt your coding agent

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. The prisma-8 skill covers the contract. 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."

Next steps

On this page