The data contract
The data contract is the single description of your data model and its storage layout. Everything in Prisma 8 is typed, planned, and verified against it.
Every Prisma 8 project has one description of its data: the models, their fields, and how they map to database tables. That description is the data contract.
For example, a blog's contract declares a User and a Post, the fields each carries, and how they relate. You author it in PSL, the Prisma schema language:
model User {
id Int @id @default(autoincrement())
email String @unique
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
userId Int
user User @relation(fields: [userId], references: [id])
}Prisma 8 compiles this into a machine-readable artifact, and the rest of the toolchain works against it: queries are type-checked against the contract, migrations are planned as changes to it, and the database is verified against it before your code runs.
Think of it as a package-lock.json for your data: an exact, versioned record of what your application expects from its database.
In Prisma 8, the contract is what you write in your code, and the schema is your database's actual structure. Some tools use these words the other way around, so keep the distinction in mind: you author a contract, and Prisma 8 checks that the database's schema satisfies it.
Why a contract
Prisma ORM's current architecture compiles your schema into generated client code. The schema knowledge exists, but it is buried in code that only the client itself can interpret.
Prisma 8 keeps the schema knowledge in the open. Your contract source compiles to two plain files: contract.json, a canonical JSON description of models, storage, and capabilities, and contract.d.ts, the TypeScript types derived from it. Both are deterministic: the same source always produces byte-identical output, so the artifacts can be diffed in code review, hashed for verification, and read directly by tools and AI agents.
The contract also identifies the exact schema version it describes. When you emit the contract, Prisma 8 computes hashes over its content, and db sign records them in a small marker inside the database. Before executing queries, Prisma 8 compares the contract it was built against with the marker in the database it is talking to. If they do not match, for example after a deploy against an unmigrated database, verification fails before any query runs.
How it works
A Prisma 8 project declares one contract source in prisma.config.ts:
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";
export default definePrismaConfig({
orm: ormConfig({
contract: "./prisma/contract.prisma",
}),
});The source is either a Prisma schema file (contract.prisma) or a TypeScript file (contract.ts). The file extension selects the authoring mode. Both modes describe the same things: models with fields and relations, the tables and columns they map to, named types, enums, and any extension-provided types.
Emitting turns the source into the artifacts:
bunx prisma@latest contract emitThis writes contract.json and contract.d.ts next to the source. From there, the rest of the toolchain takes over:
- The query APIs load
contract.d.tsto give you typed models, fields, and results. - The runtime receives
contract.jsonand verifies its hashes against the database marker. - The migration tooling diffs two contracts to plan schema changes, and
db verifychecks a live database against the current contract.
Two authoring modes, one artifact
PSL is the preferred way to author the contract: a compact language purpose-built for describing data. It is what create-prisma scaffolds, what contract infer writes when you start from an existing database, and what the examples throughout these docs use.
For the cases PSL does not cover, define models with the TypeScript builder instead. Reach for it when model definitions must be composed, generated, or shared as ordinary TypeScript modules.
Both modes produce the same contract. For an equivalent schema they emit the same contract.json, so migrations, verification, and the query APIs behave the same no matter which mode you write. You give up nothing by staying with PSL. A project declares exactly one source of truth: the file named by contract in the config. Keep the other form out of the project, or treat it as a generated reference, so the two can never disagree.
What the contract contains
The contract describes structure, not data:
- models, fields, and relations, plus how they map to tables and columns
- storage details: primary keys, unique constraints, indexes, and foreign keys
- named types, enums, and value objects
- types and capabilities contributed by extension packs, such as pgvector's
Vector - content hashes that identify this exact version of the schema
It contains no rows, no credentials, and no connection details, so committing the source and the emitted artifacts to version control is safe and expected.
Prompt your coding agent
Projects scaffolded with create-prisma@latest install Prisma 8 skills for your coding agent. The prisma-8 skill covers this page. Ask your agent to:
- "Using the prisma-8 skill, explain what our contract.json currently declares."
- "Add an Invoice model to the contract and emit it."
- "Check whether our database still satisfies the contract."
Next steps
- Model your data before writing the contract: models, keys, and relations.
- Query against the contract: every result is typed by what you authored here.
Author in PSL
Write the contract as a Prisma schema file.
Author in TypeScript
Define the same models with the typed contract builder.
The contract artifact
What is inside contract.json and contract.d.ts, and how the hashes work.
Capabilities
How Prisma 8 checks that your database supports what the contract needs.
