The data contract
Every Prisma ORM project has one description of its data: the models, their fields, and how they map to database tables. That description is the data contract, the contract.prisma file that replaced schema.prisma. For example, a blog's contract declares a User and a Post, the fields each one has, and how they relate. You author it in PSL, the Prisma Schema Language, the same language as schema.prisma:
// use prisma-8
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])
}The first line, // use prisma-8, marks the file as a Prisma ORM 8 contract rather than a Prisma ORM 7 schema, and npx prisma orm init writes it into the contract.prisma file it creates. The first non-blank line of every .prisma contract file must be // use prisma-8, because contract emit reads only the files that have it and skips any other file without a warning. When no file has the line, contract emit fails with CONTRACT.SOURCE_LOAD_FAILED. The editor extension also looks for the line before it checks, completes, or formats the file. A contract.ts file needs no header line. See Editor support.
npx prisma contract emit turns this file into two files that the CLI and your application read: contract.json and contract.d.ts. Your queries are type-checked against the contract, migrations are planned as changes to it, and npx prisma db verify checks a live database against it.
Your contract compiles to two plain files you can open and read: contract.json describes your models, how they are stored, and the database features they need, and contract.d.ts holds the TypeScript types derived from it. You can read both files in a code review and hand them to tools and coding agents.
npx prisma db migrate records in your database which contract it applied, and the first time db runs a query it checks that record and logs a warning on a mismatch. To fail instead, run npx prisma db verify in a deploy check.
A Prisma ORM project declares one contract file in prisma.config.ts:
import "dotenv/config";
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";
export default definePrismaConfig({
orm: ormConfig({
contract: "./src/prisma/contract.prisma",
db: {
connection: process.env["DATABASE_URL"]!,
},
}),
});definePrismaConfig holds the whole config: which contract file to use and how to reach your database. Your connection string is in prisma.config.ts now, and the contract has no datasource block. npx prisma orm init writes .env.example, and your DATABASE_URL goes in .env. @prisma/orm-postgres/config exports defineConfig, which the example renames to ormConfig on import. The packages are @prisma/orm-postgres for PostgreSQL, @prisma/orm-sqlite for SQLite, and @prisma/orm-mongo for MongoDB. The examples here use PostgreSQL.
To start a new project, run npm create prisma@latest -- my-app. To add Prisma ORM 8 to a project that has no Prisma ORM at all, run npx prisma orm init. If you already have a Prisma ORM 7 schema.prisma, follow the PostgreSQL upgrade guide instead, and Coming from Prisma ORM 7 lists what changed. Both npm create prisma@latest and npx prisma orm init write prisma.config.ts, the contract file, and src/prisma/db.ts, and install the database package.
The contract file is either a PSL file (contract.prisma) or a TypeScript file (contract.ts). The file extension selects the authoring mode, so to author in TypeScript you point contract at ./src/prisma/contract.ts. You can also split a PSL contract across several files by setting contract to a glob such as ./src/prisma/**/*.prisma, as Configuration shows. Both modes describe the same things: models with fields and relations, the tables and columns they map to, named types, enums, and any types that extension packages add. Extension packages are npm packages that add field types and database features. For example, @prisma/orm-extension-pgvector adds vector columns, which it stores with pgvector, a PostgreSQL extension.
After every change to the contract, run these three commands:
bunx prisma contract emit
bunx prisma migration plan
bunx prisma db migratepnpm prisma contract emit
pnpm prisma migration plan
pnpm prisma db migrateyarn prisma contract emit
yarn prisma migration plan
yarn prisma db migratenpx prisma contract emit
npx prisma migration plan
npx prisma db migratenpx prisma contract emit writes contract.json and contract.d.ts beside the contract file, so src/prisma/. npx prisma migration plan compares your contract against the last one and writes a migration. npx prisma db migrate applies it and records the match for you. When the database already matches the contract, run npx prisma db sign, which records the match without applying anything, for example after npx prisma contract infer, which writes a contract from an existing database.
db is the client you create once in src/prisma/db.ts, and npx prisma orm init writes that file for you. From a file directly inside src/, import it with import { db } from "./prisma/db" and query a model: await db.orm.public.User.all() returns every user row. From a deeper file, adjust the relative path. db.orm is the ORM client, one of the three query APIs, and public is the PostgreSQL schema, the namespace your tables are in, unless you configured a different one. Reading data covers queries.
npx prisma contract emit writes contract.json and contract.d.ts beside the contract file, so src/prisma/. npx prisma migration plan compares your contract against the last one and writes a migration. npx prisma db migrate applies it and records the match for you. When the database already matches the contract, run npx prisma db sign, which records the match without applying anything, for example after npx prisma contract infer, which writes a contract from an existing database.
db is the client you create once in src/prisma/db.ts, and npx prisma orm init writes that file for you. From a file directly inside src/, import it with import { db } from "./prisma/db" and query a model: await db.orm.public.User.all() returns every user row. From a deeper file, adjust the relative path. db.orm is the ORM client, one of the three query APIs, and public is the PostgreSQL schema, the namespace your tables are in, unless you configured a different one. Reading data covers queries.
PSL, a compact language for describing data, is the usual way to write the contract: it is what npm create prisma@latest scaffolds, and what npx prisma contract infer writes when you start from an existing database.
Define models with the TypeScript builder instead when you want to build them with code: reach for it when model definitions must be composed, generated, or shared as ordinary TypeScript modules. That page shows what a contract.ts file looks like.
Both modes produce the same contract, so migrations, database checks, and db behave the same no matter which mode you write. The config names either PSL files or one TypeScript file, never both, and Prisma ORM reads only the files it names. So do not keep both a contract.prisma and a contract.ts, because edits to the one the config does not name do nothing. To switch modes, change the path in contract and delete the old file.
The contract describes structure, not data:
- models, fields, and relations, plus how they map to tables and columns
- how the data is stored: primary keys, unique constraints, indexes, and foreign keys
- named types, which are reusable aliases for a database column type, and enums
typeblocks, also called value objects, each a reusable group of fields such as an address, stored inside its parent row with no table of its own- the types and database features that extension packages add, such as pgvector's
Vectortype
It contains no rows, no credentials, and no connection details, so committing the source, contract.json, and contract.d.ts to version control is safe and expected.
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:
- "Using the prisma-8 skill, explain what our contract.json currently declares."
- "Add an Invoice model to the contract and run prisma contract emit."
- "Check whether our database still satisfies the contract."
- Model your data before writing the contract: models, keys, and relations.
Author in PSL Write the contract as a PSL file.Author in TypeScript Define the same models with the TypeScript builder.contract.json and contract.d.ts What is inside contract.json and contract.d.ts, and how the hashes work.Supported database features How Prisma ORM checks that your database supports what the contract needs.