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.
| 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. 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:
- Edit
contract.prismaorcontract.ts. - Run
npx prisma contract emit. - Create the migration with
npx prisma migration plan, read it, then apply it withnpx prisma db migrate. - Check the database against the contract with
npx prisma db verifyin 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:
- Applying a migration records the match for you, and so does
npx prisma db initwhen it creates the structures in an empty database. - Run
npx prisma db signby hand only afternpx prisma contract inferhas written a starter contract from a database that already matches it.
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:
{
"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 modelUsermapped to a tableusersthe key isusers. The value names the model. The ORM reference covers both ways of reaching it,db.sql.public.userby table name anddb.orm.public.Userby model name.domainandstorage: your application's view, then the database's view. Each scalar field indomainrecords whether it is nullable and itscodecId.nativeTypeis the column type in the database.codecIdnames how Prisma ORM reads and writes the value, the PostgreSQL type plus a version.storageholds the tables with their columns, keys, indexes, constraints, and enum values.prisma db verifycompares it to the live database.capabilities: which database features this contract can use.npx prisma contract emitcollects them from the adapter for your database and from the packages listed inextensions: [...]inprisma.config.ts, the config fileprisma orm initwrites. 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.tsimports it.- One type per hash, such as
StorageHashandProfileHash. Each one carries the hash of that part of the contract. - Input and output types for each
typeblock in your contract.
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.
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/prismaPrompt 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
- Learn which database features the contract needs, and how Prisma ORM checks that your database has them.
- Apply the contract to a fresh database with
prisma db init. - Check a live database against the contract with
prisma db verify. - Plan schema changes between contract versions with
prisma migration plan.
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.
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.
