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
.mdto 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:
- 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
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.
The content hashes
Section titled “The content hashes”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.
Inside contract.json
Section titled “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, 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:
{
"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. 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 areUser, because the model sets no@@map, so the calls aredb.sql.public.Useranddb.orm.public.User. For a modelUsermapped to a tableusers, they aredb.sql.public.usersanddb.orm.public.User. The ORM reference covers both.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
Section titled “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<'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.
How the application consumes the artifacts
Section titled “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, 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.
Version control
Section titled “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; 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:
npx prisma contract emit
git diff --exit-code src/prismaPrompt your coding agent
Section titled “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 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."
Next steps
Section titled “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.
Related pages
Section titled “Related pages”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, samecontract.jsonandcontract.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.