Welcome. This is a contract‑first, agent‑friendly data layer.
- Docs Index — How the docs are organized and what to read next
- Architecture Overview — High-level design principles
- Testing Guide — Philosophy, patterns, and commands
- Rules Index — All Cursor rules organized by topic
- ADRs — Architecture Decision Records
- Getting Started — Build, test, and run demo
- Repo Map & Layering — Package organization and import rules
- Conventions — TypeScript, tooling, and code style
- Testing — Test commands, patterns, and organization
- Common Tasks Playbook — Add operation, split monolith, fix import
Prisma Next is a contract-first data access layer:
- Contract-first: Emit
contract.json+contract.d.ts— no executable runtime code generation - Composable DSL: Type-safe query builder (
sql().from(...).select(...)) - Machine-readable: Structured artifacts that agents can understand and manipulate
- Runtime verification: Contract hashes and guardrails ensure safety before execution
- Node.js version: Use the shell's Node. Do not run nvm/fnm or any version switcher. Source of truth is root
package.jsonengines.node. If the shell's version is wrong or commands fail, report that the shell is misconfigured and the user should configure their environment to satisfyengines.node. - Use
pnpmnotnpm! - The source of truth for the required Node version is the root
package.jsonengines.nodefield. - Never use
npx - If the shell's
node -vdoes not satisfy that, or Node/pnpm commands fail due to version, report: "Your shell is misconfigured for this repo. Configure your environment so thatnoderesolves to a version that satisfies the root package.json engines.node (e.g. set your default Node in your version manager, or use Volta)." - We use turborepo to build, generally.
pnpm buildscripts are available in each package which delegate to turborepo - If you change exported types in a workspace package consumed by other packages/examples, run that package's
pnpm buildto refreshdist/*.d.mtsdeclarations before validating downstream TypeScript usage. - When you want to typecheck, use the local
pnpm typecheckscripts instead of writingtsccommands from scratch - When you want to test, use the local
pnpm testscripts. For coverage, usepnpm test:coverage(all packages) orpnpm coverage:packages(packages only, excludes examples) - Use arktype instead of zod
- Never add file extensions to imports in TypeScript
- Don't add comments if avoidable, prefer code which expresses its intent
- Don't add exports for backwards compatibility unless requested to do so
- Always write tests before creating or modifying implementation
- Do not reexport things from one file in another, except in the
exports/folders - Don't branch on target; use adapters:
.cursor/rules/no-target-branches.mdc - Keep tests concise; omit "should":
.cursor/rules/omit-should-in-tests.mdc - Keep docs current (READMEs, rules, links):
.cursor/rules/doc-maintenance.mdc - Prefer links to canonical docs over long comments
- Never use
anytype - Never use
@ts-expect-erroroutside of negative type tests - Never use
@ts-nocheck - Never suppress biome lints
- Try to minimize type casts. Instead, prefer explicit types that would make type casts unnecessary. If type cast is unavoidable, try to minimize its scope — never cast entire object/class when casting one property would suffice.
as unknown as SomeOtherTypetype cast should be used only as a last resort and should always be accompanied by a comment explaining why it is necessary.
pnpm build # Build via Turbo
pnpm test:packages # Run package tests
pnpm test:e2e # Run e2e tests
pnpm test:integration # Run integration tests
pnpm test:all # Run all tests
pnpm coverage:packages # Coverage (packages only)
pnpm lint:deps # Validate layering/imports- Authoring: Write
schema.pslor use TypeScript builders → canonicalized Contract IR - Emission: Emitter validates and generates
contract.json+contract.d.ts - Validation:
validateContract<Contract>(json)validates structure and returns typed contract - Usage: DSL functions (
sql(),schema()) accept contract and propagate types
- Type Parameter Pattern: JSON imports lose literal types. Use
.d.tsfor precise types,validateContract()for runtime validation - ExecutionContext: Encapsulates contract, codecs, operations, and types. Pass to
schema(),sql(),orm() - Interface-Based Design: Export interfaces and factory functions, not classes
- Capability Gating: Features like
includeManyandreturning()require capabilities in contract
Organized by Domains → Layers → Planes:
- Domains: Framework (target-agnostic), SQL, Document, Targets, Extensions
- Layers: Core → Authoring → Tooling → Lanes → Runtime → Adapters
- Planes: Migration, Runtime, Shared
See architecture.config.json for the complete mapping and pnpm lint:deps to validate.
import postgres from '@prisma-next/postgres/runtime';
import type { Contract, TypeMaps } from './contract.d';
import contractJson from './contract.json' with { type: 'json' };
const db = postgres<Contract, TypeMaps>({
contractJson,
url: process.env['DATABASE_URL']!,
});
const tables = db.schema.tables;
const plan = db.sql
.from(tables.user)
.select({ id: tables.user.columns.id, email: tables.user.columns.email })
.limit(10)
.build();// CRITICAL: Type parameter must be the fully-typed Contract from contract.d.ts
const contract = validateContract<Contract>(contractJson);- Don't infer types from JSON — Use type parameter pattern with
.d.ts - validateContract requires fully-typed Contract — NOT generic
SqlContract<SqlStorage> - Type canonicalization happens at authoring time — Not during validation
- No target-specific branches in core — Use adapters instead
- Builder chaining — Methods return new instances, always chain calls
- Column access — Use
table.columns.fieldNameto avoid conflicts with table properties
- No backward‑compat shims; update call sites instead:
.cursor/rules/no-backward-compatibility.md - Package layering is enforced; fix violations rather than bypassing:
scripts/check-imports.mjsand.cursor/rules/import-validation.mdc - Capability‑gated features must be enabled in contract capabilities
- Add SQL operation:
docs/briefs/completeand.cursor/plans/add-sql-operation.md - Split monolith into modules:
.cursor/plans/split-into-modules.md - Fix import violation:
.cursor/plans/fix-import-violation.md - Shape and deliver a project (spec → plan → implement):
.agents/rules/drive-project-workflow.mdc(artifacts live underprojects/, seeprojects/README.md)
See docs/architecture docs/subsystems/:
- Data Contract — Contract structure and semantics
- Contract Emitter & Types — How contracts are generated
- Query Lanes — SQL DSL, ORM, Raw SQL surfaces
- Runtime & Middleware Framework — Execution pipeline and middleware
- Adapters & Targets — Postgres adapter, capability gating
- Error Handling — Error envelope and stable codes
- Migration System — Schema migrations
- Significant refactors to rule scope (
alwaysApply) or architecture docs - Changes that affect demo, examples, or CI
Remember: This is a prototype. Focus on clear docs that reflect implemented behavior.