Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/prisma/prisma-next/llms.txt

Use this file to discover all available pages before exploring further.

The starting point for every Prisma Next project is defining your data model. Prisma Next supports two authoring modes — Prisma Schema Language (PSL) and a TypeScript builder API — that both produce the same deterministic contract.json artifact. Once emitted, that artifact drives query type safety, runtime verification, and migration planning without any further code generation.

Authoring modes

Prisma Schema Language uses a declarative, human-readable syntax. Models, fields, and relations are defined in a .psl file using familiar Prisma syntax.
// schema.psl
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  posts     Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  userId    Int
  createdAt DateTime @default(now())
  user      User     @relation(fields: [userId], references: [id])
}
After authoring, run the emit command to produce the contract artifacts:
prisma-next contract emit schema.psl -o .prisma
# Generates: .prisma/contract.json + .prisma/contract.d.ts

The emit command

prisma-next contract emit reads your contract source (PSL or TypeScript) and produces two artifacts in your output directory:
# From a config file (recommended)
prisma-next contract emit

# Explicit PSL file
prisma-next contract emit schema.psl -o .prisma

# Verbose output with timing
prisma-next contract emit -v
The command:
  1. Loads the contract source (bundles TypeScript with esbuild; validates import allowlist for TS mode)
  2. Validates that the resulting object is pure data — no functions, no getters, JSON-serializable
  3. Canonicalizes the contract (lexicographic key ordering, normalized scalars)
  4. Computes storageHash, profileHash, and optional executionHash via SHA-256 over the canonical JSON
  5. Writes contract.json and generates contract.d.ts
The contract emit command does not connect to a database. You can run it without a driver configured.

What gets emitted

contract.json

The canonical JSON artifact contains everything needed to verify queries at runtime and plan migrations:
{
  "schemaVersion": "1",
  "targetFamily": "sql",
  "target": "postgres",
  "profileHash": "sha256:1a8dbe044289f30a1de958fe800cc5a8378b285d2e126a8c44b58864bac2c18e",
  "roots":   { "user": "User", "post": "Post" },
  "models":  { "User": { "fields": {}, "relations": {}, "storage": {} }, "Post": {} },
  "storage": { "storageHash": "sha256:…", "tables": {} },
  "capabilities": { "postgres": { "lateral": true, "jsonAgg": true } },
  "extensionPacks": {},
  "meta": {},
  "_generated": {
    "warning":    "⚠️  GENERATED FILE - DO NOT EDIT",
    "message":    "This file is automatically generated by \"prisma-next contract emit\".",
    "regenerate": "To regenerate, run: prisma-next contract emit"
  }
}
Do not edit contract.json by hand. The _generated warning header is there as a reminder.

contract.d.ts

The companion TypeScript declaration file exports branded types for every model and codec in your contract. Query DSL and ORM surfaces import from this file to give your queries fully-typed results:
import type { Contract } from './.prisma/contract.d';
import contractJson from './.prisma/contract.json' with { type: 'json' };

const db = postgres<Contract>({ contractJson });

const users = await db.orm.User
  .select('id', 'email')
  .take(10)
  .all();
// users: Array<{ id: number; email: string }>

How contractHash is computed

Prisma Next uses SHA-256 over the canonicalized contract JSON to produce the storageHash. Canonicalization rules include:
  • All object keys sorted lexicographically at every nesting level
  • Scalar values normalized (numbers, strings, booleans in standard forms)
  • Default expressions normalized (e.g. now() is always the same string)
  • Array ordering preserved where order is semantically meaningful
Because the same schema always produces the same canonical bytes, storageHash is stable across machines, operating systems, and Node.js versions. The runtime embeds this hash in every query plan and verifies it against the database marker before execution.

No-emit workflow

If you author your contract in TypeScript, you can skip the explicit emit step entirely during development. Types flow directly from the contract object through the DSL generics — no file needs to be written to disk.
// vite.config.ts
import { prismaVitePlugin } from '@prisma-next/vite-plugin-contract-emit';

export default {
  plugins: [
    prismaVitePlugin({
      debounceMs: 150, // optional: debounce for re-emit on file changes
      logLevel: 'info', // optional: 'silent' | 'info' | 'debug'
    }),
  ],
};
In this mode the Vite (or esbuild/Next.js) plugin auto-emits contract.json whenever the contract module changes. CI still runs prisma-next contract emit explicitly to validate determinism before deployment.
PSL-first and TypeScript-first authoring produce identical storageHash values for the same schema. The canonical JSON representation is the same regardless of which authoring surface you use.

Build docs developers (and LLMs) love