prisma-next-contract

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Prisma Next — Contract Authoring

Prisma Next — 契约编写

Edit your data contract. Prisma handles the rest.
The data contract is the single source of truth for your data layer. You edit a contract source —
contract.prisma
(PSL, the canonical surface) or
contract.ts
(TypeScript builder) — and the framework derives types, migrations, and runtime configuration from it. The three-step user model:
  1. You edit your data contract.
  2. The system plans the migrations for you. (
    prisma-next-migrations
    )
  3. If you need data migrations, you edit
    migration.ts
    and execute it.
    (
    prisma-next-migrations
    )
Behind step 1 the agent runs
prisma-next contract emit
after every contract edit (or installs the Vite plugin so the bundler runs it on save — see
prisma-next-build
). Emit reads the contract source through the provider the façade picks based on the file extension of
contract:
in
prisma-next.config.ts
, then writes two artefacts colocated with the source:
  • contract.json
    — the canonical, content-hashed Contract IR. Read by the planner, the runtime, and
    db verify
    .
  • contract.d.ts
    — the precise TypeScript types the runtime + lanes propagate when you import
    Contract
    from it.
Both files are emitted artefacts. Edit the source; never the JSON or
.d.ts
.
编辑你的数据契约,其余工作由Prisma完成。
数据契约是数据层的唯一可信来源。你编辑契约源文件——
contract.prisma
(PSL,标准交互层)或
contract.ts
(TypeScript构建器)——框架会从中派生类型、迁移脚本和运行时配置。三步用户流程:
  1. 编辑你的数据契约
  2. 系统为你规划迁移方案
    prisma-next-migrations
  3. 如需数据迁移,编辑
    migration.ts
    并执行
    prisma-next-migrations
在步骤1背后,每次编辑契约后代理会运行
prisma-next contract emit
(或安装Vite插件,让打包器在保存时自动运行——详见
prisma-next-build
)。Emit会根据
prisma-next.config.ts
contract:
字段的文件扩展名,通过外观选择的提供者读取契约源,然后在源文件旁生成两个产物:
  • contract.json
    ——标准、带内容哈希的契约IR。供规划器、运行时和
    db verify
    读取。
  • contract.d.ts
    ——运行时和lanes在你导入
    Contract
    时传播的精确TypeScript类型。
这两个文件都是生成产物。请编辑源文件,切勿修改JSON或
.d.ts
文件。

When to Use

适用场景

  • User wants to add, change, or remove a model / field / relation.
  • User wants to add an index, unique constraint, or enum.
  • User wants to use a custom type from an extension (
    pgvector.Vector(length: 1536)
    ,
    cipherstash.EncryptedString({...})
    ).
  • User wants to install or configure an extension via
    extensions: [...]
    in
    prisma-next.config.ts
    .
  • User is migrating between authoring sources (PSL ↔ TypeScript builder).
  • User received
    PN-CLI-4002
    ,
    PN-CLI-4003
    , or
    PN-CLI-4011
    from
    contract emit
    .
  • User mentions: schema, fields, models, attributes, prisma schema, PSL, contract.prisma, contract.ts, contract.json, contract.d.ts, contract emit, façade imports,
    @prisma-next/postgres/config
    ,
    @prisma-next/postgres/contract-builder
    , extensions, extensionPacks, pgvector, cipherstash, postgis, paradedb, validations, callbacks, soft delete, paranoid, scopes
    . (The last cluster routes to What Prisma Next doesn't do yet below.)
  • 用户想要添加、修改或删除模型/字段/关联关系
  • 用户想要添加索引、唯一约束或枚举
  • 用户想要使用扩展提供的自定义类型(如
    pgvector.Vector(length: 1536)
    cipherstash.EncryptedString({...})
  • 用户想要通过
    prisma-next.config.ts
    中的
    extensions: [...]
    安装或配置扩展
  • 用户在不同编写源之间迁移(PSL ↔ TypeScript构建器)
  • 用户在运行
    contract emit
    时收到
    PN-CLI-4002
    PN-CLI-4003
    PN-CLI-4011
    错误
  • 用户提及:schema、字段、模型、属性、prisma schema、PSL、contract.prisma、contract.ts、contract.json、contract.d.ts、contract emit、外观导入、
    @prisma-next/postgres/config
    @prisma-next/postgres/contract-builder
    、extensions、extensionPacks、pgvector、cipherstash、postgis、paradedb、验证、回调、软删除、偏执模式、作用域。(最后一组内容对应下方「Prisma Next暂不支持的功能」)

When Not to Use

不适用场景

  • User wants to apply a contract change to the DB →
    prisma-next-migrations
    .
  • User wants to write a query against the contract →
    prisma-next-queries
    .
  • User wants to wire
    db.ts
    (runtime entry point, middleware, env config) →
    prisma-next-runtime
    .
  • User wants the Vite / bundler integration →
    prisma-next-build
    .
  • User wants to set up Prisma Next for the first time →
    prisma-next-quickstart
    .
  • User wants a deeper read of a single structured error envelope →
    prisma-next-debug
    .
  • User wants to file a missing-feature request →
    prisma-next-feedback
    .
  • 用户想要将契约变更应用到数据库 → 使用
    prisma-next-migrations
  • 用户想要针对契约编写查询 → 使用
    prisma-next-queries
  • 用户想要配置
    db.ts
    (运行时入口、中间件、环境配置)→ 使用
    prisma-next-runtime
  • 用户想要Vite/打包器集成 → 使用
    prisma-next-build
  • 用户想要首次设置Prisma Next → 使用
    prisma-next-quickstart
  • 用户想要深入阅读单个结构化错误信息 → 使用
    prisma-next-debug
  • 用户想要提交缺失功能请求 → 使用
    prisma-next-feedback

Key Concepts

核心概念

  • The
    @prisma-next/<target>
    façade is the only surface user-authored code imports from.
    For a Postgres app:
    @prisma-next/postgres/config
    ,
    @prisma-next/postgres/contract-builder
    ,
    @prisma-next/postgres/control
    ,
    @prisma-next/postgres/runtime
    . Mongo has the same layout (
    @prisma-next/mongo/config
    ,
    @prisma-next/mongo/contract-builder
    ,
    @prisma-next/mongo/runtime
    ). Each extension publishes its own façade —
    @prisma-next/extension-pgvector/control
    ,
    @prisma-next/extension-cipherstash/control
    ,
    @prisma-next/extension-postgis/control
    ,
    @prisma-next/extension-paradedb/control
    . Never reach into
    @prisma-next/cli/*
    ,
    @prisma-next/family-*
    ,
    @prisma-next/target-*
    ,
    @prisma-next/adapter-*
    ,
    @prisma-next/driver-*
    , or
    @prisma-next/sql-contract-*
    from user code.
    The façade bakes the family / target / adapter / driver wiring in. See Common Pitfalls #4.
  • Contract source. A file the framework reads and lowers to the canonical Contract IR. Two flavours, both first-class:
    • contract.prisma
      (PSL)
      — schema-flavoured DSL. Canonical for typical apps and brownfield Prisma users. Wired by
      contract: './<path>/contract.prisma'
      — the
      defineConfig
      façade detects the
      .prisma
      extension and routes through the PSL provider.
    • contract.ts
      (TypeScript builder)
      — programmatic authoring with
      defineContract({...}, ({ field, model, rel, type }) => ({...}))
      from
      @prisma-next/postgres/contract-builder
      (or
      @prisma-next/mongo/contract-builder
      ). Wired by
      contract: './<path>/contract.ts'
      — the façade detects the
      .ts
      extension and routes through the TS provider. Use when you need programmatic composition (per-tenant variants, generated fields) or constructs PSL doesn't yet express (e.g. registering a parameterised extension type — see pgvector's contract).
  • prisma-next.config.ts
    .
    Wires the contract source, the database connection, the migrations directory, and any installed extensions. Use
    defineConfig({...})
    from
    @prisma-next/postgres/config
    (or
    @prisma-next/mongo/config
    ). The four fields the façade accepts:
    contract
    (path string —
    .prisma
    or
    .ts
    ),
    db
    (
    { connection?: string }
    ),
    extensions
    (array of control descriptors),
    migrations
    (
    { dir?: string }
    ). The output path for
    contract.json
    is auto-derived from
    contract
    (e.g.
    ./src/prisma/contract.prisma
    ./src/prisma/contract.json
    ).
  • Emit pipeline.
    prisma-next contract emit --config <path>?
    reads
    prisma-next.config.ts
    , calls the provider the façade picked, validates the resulting Contract, then atomically writes
    contract.json
    +
    contract.d.ts
    colocated with the source.
  • Extension namespaces. Extensions contribute namespaced constructors (
    pgvector.Vector(length: 1536)
    ,
    cipherstash.EncryptedString({equality: true})
    ) and helper presets. Install them by adding the descriptor to two places, with two different field names because the surfaces consume two different descriptor types:
    • In the config façade:
      extensions: [pgvector]
      — array of control descriptors imported from
      @prisma-next/extension-<name>/control
      . The façade's underlying field is
      extensionPacks
      ; the façade renames it to
      extensions
      .
    • In the TS builder's
      defineContract
      (only when authoring
      contract.ts
      ):
      extensionPacks: { pgvector }
      — record of pack descriptors imported from
      @prisma-next/extension-<name>/pack
      .
  • Contract space. Every package that emits a contract owns its own contract space — a
    prisma-next.config.ts
    at package root, a contract source, the colocated emitted artefacts, and a
    migrations/
    directory. There are two intentional on-disk layouts, picked by whether the contract space is the consuming application or a contract-space package (an extension, an internal aggregate-root package, etc.):
    • Application layout (what you use when building an app).
      prisma-next.config.ts
      at repo root;
      src/prisma/contract.{prisma,ts}
      ;
      src/prisma/contract.{json,d.ts}
      colocated;
      src/prisma/db.ts
      colocated; migrations under
      migrations/app/<timestamp>_<slug>/
      . The
      app/
      segment is the consuming application's space-id; extension space-ids land in sibling
      migrations/<extension-space-id>/
      directories that the extension packages manage. This is what
      examples/prisma-next-demo
      uses.
      prisma-next init
      currently scaffolds something different (
      prisma/...
      at repo root) — that's a defect (TML-2532); the canonical layout is what every command actually expects to see.
    • Contract-space-package layout (what you use when publishing a contract-space package — extensions, internal monorepo packages).
      prisma-next.config.ts
      at package root;
      src/contract.{prisma,ts}
      directly (no
      prisma/
      subdir);
      src/contract.{json,d.ts}
      colocated;
      migrations/<timestamp>_<slug>/
      directly under
      migrations/
      (no
      <space-id>
      segment — the package is a single space). Documented in
      .cursor/rules/contract-space-package-layout.mdc
      and ADR 212.
    Both layouts let
    defineConfig
    's
    contract:
    path point at the source; the framework derives everything else (emit output, migration root) from there. Pick the layout that matches what you're building and stick with it — don't mix.
  • @prisma-next/<target>
    外观是用户代码唯一可导入的交互层
    。对于Postgres应用:
    @prisma-next/postgres/config
    @prisma-next/postgres/contract-builder
    @prisma-next/postgres/control
    @prisma-next/postgres/runtime
    。Mongo有相同的结构(
    @prisma-next/mongo/config
    @prisma-next/mongo/contract-builder
    @prisma-next/mongo/runtime
    )。每个扩展都发布自己的外观——
    @prisma-next/extension-pgvector/control
    @prisma-next/extension-cipherstash/control
    @prisma-next/extension-postgis/control
    @prisma-next/extension-paradedb/control
    切勿从用户代码中导入
    @prisma-next/cli/*
    @prisma-next/family-*
    @prisma-next/target-*
    @prisma-next/adapter-*
    @prisma-next/driver-*
    @prisma-next/sql-contract-*
    。外观已内置了family/target/adapter/driver的配置。详见「常见陷阱」第4条。
  • 契约源文件:框架读取并转换为标准契约IR的文件。有两种形式,均为一等公民:
    • contract.prisma
      (PSL)
      :类Schema的领域特定语言。对典型应用和遗留Prisma用户来说是标准选择。通过
      contract: './<path>/contract.prisma'
      配置——
      defineConfig
      外观会检测
      .prisma
      扩展名并通过PSL提供者处理。
    • contract.ts
      (TypeScript构建器)
      :使用
      @prisma-next/postgres/contract-builder
      (或
      @prisma-next/mongo/contract-builder
      )中的
      defineContract({...}, ({ field, model, rel, type }) => ({...}))
      进行程序化编写。通过
      contract: './<path>/contract.ts'
      配置——外观会检测
      .ts
      扩展名并通过TS提供者处理。适用于需要程序化组合(多租户变体、生成字段)或PSL暂不支持的结构(例如注册参数化扩展类型——详见pgvector的契约)。
  • prisma-next.config.ts
    :配置契约源文件、数据库连接、迁移目录和已安装的扩展。使用
    @prisma-next/postgres/config
    (或
    @prisma-next/mongo/config
    )中的
    defineConfig({...})
    。外观接受四个字段:
    contract
    (路径字符串——
    .prisma
    .ts
    )、
    db
    { connection?: string }
    )、
    extensions
    (控制描述符数组)、
    migrations
    { dir?: string }
    )。
    contract.json
    的输出路径会自动从
    contract
    字段派生(例如
    ./src/prisma/contract.prisma
    ./src/prisma/contract.json
    )。
  • 生成流水线
    prisma-next contract emit --config <path>?
    读取
    prisma-next.config.ts
    ,调用外观选择的提供者,验证生成的契约,然后原子性地在源文件旁写入
    contract.json
    +
    contract.d.ts
  • 扩展命名空间:扩展提供命名空间构造器(
    pgvector.Vector(length: 1536)
    cipherstash.EncryptedString({equality: true})
    )和辅助预设。需要在两个位置添加描述符,因不同交互层使用不同类型的描述符:
    • 在配置外观中
      extensions: [pgvector]
      ——从
      @prisma-next/extension-<name>/control
      导入的控制描述符数组。外观的底层字段是
      extensionPacks
      ,外观将其重命名为
      extensions
    • 在TS构建器的
      defineContract
      中(仅当编写
      contract.ts
      时)
      extensionPacks: { pgvector }
      ——从
      @prisma-next/extension-<name>/pack
      导入的描述符对象。
  • 契约空间:每个生成契约的包都拥有自己的契约空间——包根目录下的
    prisma-next.config.ts
    、契约源文件、旁置的生成产物,以及
    migrations/
    目录。有两种明确的磁盘布局,取决于契约空间是消费应用还是契约空间包(扩展、内部聚合根包等):
    • 应用布局(构建应用时使用)。仓库根目录下的
      prisma-next.config.ts
      src/prisma/contract.{prisma,ts}
      ;旁置的
      src/prisma/contract.{json,d.ts}
      ;旁置的
      src/prisma/db.ts
      ;迁移脚本位于
      migrations/app/<timestamp>_<slug>/
      app/
      是消费应用的空间ID;扩展的空间ID位于同级的
      migrations/<extension-space-id>/
      目录,由扩展包管理。
      examples/prisma-next-demo
      使用的就是这种布局。
      prisma-next init
      目前生成的结构不同(仓库根目录下的
      prisma/...
      )——这是一个缺陷(TML-2532);所有命令实际期望的是标准布局。
    • 契约空间包布局发布契约空间包时使用——扩展、内部单体仓库包)。包根目录下的
      prisma-next.config.ts
      ;直接在
      src/contract.{prisma,ts}
      (无
      prisma/
      子目录);旁置的
      src/contract.{json,d.ts}
      ;迁移脚本直接位于
      migrations/<timestamp>_<slug>/
      (无
      <space-id>
      段——包本身就是单个空间)。文档见
      .cursor/rules/contract-space-package-layout.mdc
      和ADR 212。
    两种布局都允许
    defineConfig
    contract:
    路径指向源文件;框架会从中派生其他所有内容(生成输出、迁移根目录)。选择与你构建内容匹配的布局并坚持使用——不要混合。

Diagnostic codes you route on

需关注的诊断代码

prisma-next contract emit
surfaces structured errors with stable codes; branch on
code
rather than message text.
CodeMeaningNext move
PN-CLI-4002
Contract configuration missing
contract
not set in
prisma-next.config.ts
.
Add
contract: './src/prisma/contract.prisma'
(app layout) or
'./src/contract.prisma'
(contract-space-package layout) — likewise for
.ts
sources — to
defineConfig({...})
from
@prisma-next/postgres/config
.
PN-CLI-4003
Contract validation failed
Source loaded but the Contract IR failed structural validation.Read
meta.diagnostics
/
meta.issues
for the offending model/field, fix the source, re-emit.
PN-CLI-4011
Missing extension packs in config
The contract uses a namespaced constructor (e.g.
pgvector.Vector(...)
) but
extensions
in the config does not list a matching descriptor.
meta.missingExtensionPacks
names them.
Install the package, import its control descriptor (
import pgvector from '@prisma-next/extension-pgvector/control'
), add it to
extensions: [...]
in
prisma-next.config.ts
.
prisma-next contract emit
会显示带有稳定代码的结构化错误;请根据
code
而非错误消息文本进行处理。
代码含义下一步操作
PN-CLI-4002
缺少契约配置
prisma-next.config.ts
中未设置
contract
字段
@prisma-next/postgres/config
defineConfig({...})
中添加
contract: './src/prisma/contract.prisma'
(应用布局)或
'./src/contract.prisma'
(契约空间包布局)——
.ts
源文件同理。
PN-CLI-4003
契约验证失败
已加载源文件,但契约IR未通过结构验证查看
meta.diagnostics
/
meta.issues
找到有问题的模型/字段,修复源文件后重新生成。
PN-CLI-4011
配置中缺少扩展包
契约使用了命名空间构造器(如
pgvector.Vector(...)
),但配置中的
extensions
未列出匹配的描述符。
meta.missingExtensionPacks
会列出缺失的扩展。
安装对应包,导入其控制描述符(
import pgvector from '@prisma-next/extension-pgvector/control'
),添加到
prisma-next.config.ts
extensions: [...]
中。

Workflow — Read the contract source of truth

流程 — 读取契约可信源文件

The concept: every contract change starts by locating the source file. The config is authoritative — read
prisma-next.config.ts
, find the
contract:
field (a path string under the façade), and open the file it points at. The same field tells you the installed
extensions: [...]
.
bash
cat prisma-next.config.ts
If
contract:
ends in
.prisma
, the source is PSL; if it ends in
.ts
, the source is the TS builder. If
prisma-next.config.ts
is missing, route to
prisma-next-quickstart
.
核心思路:每次契约变更都从定位源文件开始。配置文件是权威来源——读取
prisma-next.config.ts
,找到
contract:
字段(外观下的路径字符串),打开它指向的文件。该字段还会告诉你已安装的
extensions: [...]
bash
cat prisma-next.config.ts
如果
contract:
.prisma
结尾,源文件是PSL;如果以
.ts
结尾,源文件是TS构建器。如果
prisma-next.config.ts
缺失,引导至
prisma-next-quickstart

Workflow — Edit a model / field / relation (PSL)

流程 — 编辑模型/字段/关联关系(PSL)

The concept: PSL models lower to tables (or collections, on Mongo); fields lower to columns;
@relation(...)
declares the FK side. Add the relation only on the owning side — the framework derives the back-reference automatically.
prisma
model User {
  id    Int    @id @default(autoincrement())
  email String @unique
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  authorId Int
  author   User   @relation(fields: [authorId], references: [id], onDelete: Cascade)

  @@unique([title, authorId])
  @@index([authorId])
}
Then run
pnpm prisma-next contract emit
(or rely on the Vite plugin — see
prisma-next-build
). Specify cascade behaviour explicitly with
onDelete
/
onUpdate
; the default is
Restrict
.
PSL alias surface for repeated types lives in a top-level
types {}
block:
prisma
types {
  Email = String
}

model User {
  id    Int    @id @default(autoincrement())
  email Email  @unique
}
Note: scalar lists (e.g.
String[]
) and implicit Prisma-ORM many-to-many (list nav on both sides without a join model) are rejected by the SQL interpreter — use a join model. Composite/embeddable types (
type Address { ... }
with
address Address
on a model) are not supported by the SQL contract today.
核心思路:PSL模型对应表(Mongo中对应集合);字段对应列;
@relation(...)
声明外键端。仅在拥有端添加关联关系——框架会自动派生反向引用。
prisma
model User {
  id    Int    @id @default(autoincrement())
  email String @unique
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  authorId Int
  author   User   @relation(fields: [authorId], references: [id], onDelete: Cascade)

  @@unique([title, authorId])
  @@index([authorId])
}
然后运行
pnpm prisma-next contract emit
(或依赖Vite插件——详见
prisma-next-build
)。使用
onDelete
/
onUpdate
显式指定级联行为;默认是
Restrict
PSL中重复类型的别名定义在顶层
types {}
块中:
prisma
types {
  Email = String
}

model User {
  id    Int    @id @default(autoincrement())
  email Email  @unique
}
注意:标量列表(如
String[]
)和隐式Prisma-ORM多对多(两端都有列表导航但无连接模型)会被SQL解释器拒绝——请使用连接模型。组合/可嵌入类型(
type Address { ... }
并在模型中使用
address Address
)目前不被SQL契约支持。

Workflow — Edit a model / field / relation (TS builder)

流程 — 编辑模型/字段/关联关系(TS构建器)

The concept: same model, different authoring surface. The façade re-exports
defineContract
,
field
,
model
,
rel
, plus the
family
/
target
packs as default exports of
@prisma-next/postgres/family
and
@prisma-next/postgres/target
. Use the callback overload (
defineContract({...}, ({ field, model, rel, type }) => ({...}))
) to get the higher-level helpers (
field.text()
,
field.id.uuidv7()
,
field.temporal.createdAt()
,
type.sql.String(35)
).
typescript
import sqlFamily from '@prisma-next/postgres/family';
import { defineContract } from '@prisma-next/postgres/contract-builder';
import postgresPack from '@prisma-next/postgres/target';

export const contract = defineContract(
  {
    family: sqlFamily,
    target: postgresPack,
  },
  ({ field, model }) => ({
    models: {
      User: model('User', {
        fields: {
          id: field.id.uuidv7(),
          email: field.text().unique(),
          createdAt: field.temporal.createdAt(),
        },
      }).sql({ table: 'app_user' }),
    },
  }),
);
Then
pnpm prisma-next contract emit
. The
field.<scalar>()
helpers are only available inside the callback overload; outside the callback only
field.column(...)
,
field.generated(...)
,
field.namedType(...)
exist.
For Mongo, swap every
@prisma-next/postgres/*
import for
@prisma-next/mongo/*
. The Mongo builder also exposes
index
and
valueObject
.
核心思路:模型逻辑相同,仅编写交互层不同。外观会重新导出
defineContract
field
model
rel
,以及
family
/
target
包作为
@prisma-next/postgres/family
@prisma-next/postgres/target
的默认导出。使用回调重载(
defineContract({...}, ({ field, model, rel, type }) => ({...}))
)获取高级辅助函数(
field.text()
field.id.uuidv7()
field.temporal.createdAt()
type.sql.String(35)
)。
typescript
import sqlFamily from '@prisma-next/postgres/family';
import { defineContract } from '@prisma-next/postgres/contract-builder';
import postgresPack from '@prisma-next/postgres/target';

export const contract = defineContract(
  {
    family: sqlFamily,
    target: postgresPack,
  },
  ({ field, model }) => ({
    models: {
      User: model('User', {
        fields: {
          id: field.id.uuidv7(),
          email: field.text().unique(),
          createdAt: field.temporal.createdAt(),
        },
      }).sql({ table: 'app_user' }),
    },
  }),
);
然后运行
pnpm prisma-next contract emit
field.<scalar>()
辅助函数仅在回调重载内可用;回调外仅存在
field.column(...)
field.generated(...)
field.namedType(...)
对于Mongo,将所有
@prisma-next/postgres/*
导入替换为
@prisma-next/mongo/*
。Mongo构建器还提供
index
valueObject

Workflow — Add an extension-typed scalar (pgvector)

流程 — 添加扩展类型的标量(pgvector)

The concept: an extension contributes a namespace (
pgvector.*
) plus two descriptor flavours — a control descriptor for the config façade and a pack descriptor for the TS builder. Register the control descriptor in
defineConfig.extensions
(array form). If you're authoring with the TS builder, also register the pack descriptor in
defineContract.extensionPacks
(record form). Then reference the namespaced constructor from the contract.
prisma-next.config.ts
:
typescript
import pgvector from '@prisma-next/extension-pgvector/control';
import { defineConfig } from '@prisma-next/postgres/config';

export default defineConfig({
  contract: './src/prisma/contract.prisma',
  extensions: [pgvector],
});
src/prisma/contract.prisma
:
prisma
model Document {
  id        Int                          @id @default(autoincrement())
  content   String
  embedding pgvector.Vector(length: 1536)
}
Emit. The named-type lowering puts
vector(1536)
on the column and the type map in
contract.d.ts
carries the right TS type.
If you reference
pgvector.*
without registering the pack in the config, emit fails with
PN-CLI-4011
and
meta.missingExtensionPacks: ['pgvector']
. The envelope's
fix
text says "Add the missing extension descriptors to
extensions
in prisma-next.config.ts"
— that field name matches the façade.
For canonical worked examples covering single and multi-extension setups, read
examples/multi-extension-monorepo/app/prisma-next.config.ts
,
examples/cipherstash-integration/prisma-next.config.ts
, and
examples/prisma-next-postgis-demo/prisma-next.config.ts
.
核心思路:扩展提供命名空间(
pgvector.*
)以及两种描述符——配置外观用的控制描述符和TS构建器用的描述符。在
defineConfig.extensions
(数组形式)中注册控制描述符。如果使用TS构建器编写,还需在
defineContract.extensionPacks
(对象形式)中注册包描述符。然后在契约中引用命名空间构造器。
prisma-next.config.ts
:
typescript
import pgvector from '@prisma-next/extension-pgvector/control';
import { defineConfig } from '@prisma-next/postgres/config';

export default defineConfig({
  contract: './src/prisma/contract.prisma',
  extensions: [pgvector],
});
src/prisma/contract.prisma
:
prisma
model Document {
  id        Int                          @id @default(autoincrement())
  content   String
  embedding pgvector.Vector(length: 1536)
}
运行生成命令。命名类型转换会在列上设置
vector(1536)
,且
contract.d.ts
中的类型映射会携带正确的TS类型。
如果未在配置中注册包就引用
pgvector.*
,生成会失败并返回
PN-CLI-4011
meta.missingExtensionPacks: ['pgvector']
。错误信息的
fix
文本会提示*"在prisma-next.config.ts的
extensions
中添加缺失的扩展描述符"*——该字段名称与外观一致。
有关单扩展和多扩展配置的标准示例,请查看
examples/multi-extension-monorepo/app/prisma-next.config.ts
examples/cipherstash-integration/prisma-next.config.ts
examples/prisma-next-postgis-demo/prisma-next.config.ts

Workflow — Polymorphism (
@@discriminator
/
@@base
)

流程 — 多态性(
@@discriminator
/
@@base

The concept (SQL targets): one base model declares the discriminator field; each variant model declares its base + discriminator value. The variant chooses STI vs MTI by whether it sets
@@map(...)
: no
@@map
means the variant inherits the base's table (single-table inheritance);
@@map("variant_table")
means the variant gets its own table joined 1:1 by primary key (multi-table inheritance).
prisma
model Task {
  id    Int    @id @default(autoincrement())
  title String
  type  String

  @@discriminator(type)
  @@map("tasks")
}

// STI variant — shares the `tasks` table.
model Bug {
  severity String

  @@base(Task, "bug")
}

// MTI variant — joins to `tasks` via PK; carries its own `features` table.
model Feature {
  priority Int

  @@base(Task, "feature")
  @@map("features")
}
Verify the polymorphism syntax against the interpreter tests if in doubt:
packages/2-sql/2-authoring/contract-psl/test/interpreter.polymorphism.test.ts
.
Mongo has no schema layer, so polymorphism on Mongo is modelled by an explicit
discriminator
field on the model in the TS builder (see
@prisma-next/mongo/contract-builder
);
@@base
/
@@discriminator
PSL attributes are SQL-only.
Querying the variants is a runtime concern — see
prisma-next-queries
.
核心思路(SQL目标):一个基础模型声明鉴别器字段;每个变体模型声明其基础模型+鉴别器值。变体通过**是否设置
@@map(...)
**选择STI还是MTI:不设置
@@map
意味着变体继承基础模型的表(单表继承);设置
@@map("variant_table")
意味着变体拥有自己的表,通过主键1:1关联(多表继承)。
prisma
model Task {
  id    Int    @id @default(autoincrement())
  title String
  type  String

  @@discriminator(type)
  @@map("tasks")
}

// STI变体——共享`tasks`表
model Bug {
  severity String

  @@base(Task, "bug")
}

// MTI变体——通过主键关联`tasks`;拥有自己的`features`表
model Feature {
  priority Int

  @@base(Task, "feature")
  @@map("features")
}
如有疑问,请对照解释器测试验证多态性语法:
packages/2-sql/2-authoring/contract-psl/test/interpreter.polymorphism.test.ts
Mongo没有Schema层,因此Mongo上的多态性通过TS构建器中模型的显式
discriminator
字段建模(详见
@prisma-next/mongo/contract-builder
);
@@base
/
@@discriminator
PSL属性仅适用于SQL。
查询变体是运行时相关的操作——详见
prisma-next-queries

Workflow — Brownfield introspection

流程 — 遗留系统自省

The concept: pull a contract source out of an existing database and continue from there.
prisma-next contract infer --db <url>
reads the live schema and writes a
contract.prisma
file. It stops there — follow it with
contract emit
and (when the schema matches a pinned hash)
db sign
as separate steps.
bash
pnpm prisma-next contract infer --db $DATABASE_URL --output ./src/prisma/contract.prisma
pnpm prisma-next contract emit
核心思路:从现有数据库中提取契约源文件并继续开发。
prisma-next contract infer --db <url>
读取实时Schema并写入
contract.prisma
文件。操作到此为止——后续需分别执行
contract emit
和(当Schema匹配固定哈希时)
db sign
步骤。
bash
pnpm prisma-next contract infer --db $DATABASE_URL --output ./src/prisma/contract.prisma
pnpm prisma-next contract emit

Common Pitfalls

常见陷阱

  1. Forgetting to re-emit after an edit.
    contract.json
    and
    contract.d.ts
    go stale; downstream typecheck and
    migration plan
    see the old shape. Re-emit, or install the Vite plugin (
    prisma-next-build
    ).
  2. Editing the emitted artefacts.
    contract.json
    and
    contract.d.ts
    are emitted; edits there round-trip away on the next emit. Edit the source.
  3. Wrong factory/import path for the TS builder.
    defineContract
    ,
    field
    ,
    model
    ,
    rel
    come from
    @prisma-next/postgres/contract-builder
    (or
    @prisma-next/mongo/contract-builder
    ). Outside the callback overload, the available field constructors are
    field.column(...)
    ,
    field.generated(...)
    ,
    field.namedType(...)
    .
  4. Reaching into internal packages from user code. User-authored files (
    prisma-next.config.ts
    ,
    contract.ts
    ,
    db.ts
    , control clients) import only from
    @prisma-next/<target>/<subpath>
    and
    @prisma-next/extension-<name>/<subpath>
    . Imports from
    @prisma-next/cli/*
    ,
    @prisma-next/family-*
    ,
    @prisma-next/target-*
    ,
    @prisma-next/adapter-*
    ,
    @prisma-next/driver-*
    , or
    @prisma-next/sql-contract-*
    are framework-internal — the façade composes them for you. If a façade subpath you need is missing for your target, see What Prisma Next doesn't do yet and route to
    prisma-next-feedback
    (track via TML-2526). The canonical worked examples are
    examples/multi-extension-monorepo/app/prisma-next.config.ts
    ,
    examples/cipherstash-integration/prisma-next.config.ts
    , and
    examples/prisma-next-postgis-demo/prisma-next.config.ts
    .
  5. Confusing
    extensions
    (config façade) with
    extensionPacks
    (TS builder).
    Same packs, two surfaces, two field names:
    defineConfig({ extensions: [pgvector] })
    (array of control descriptors from
    @prisma-next/extension-<name>/control
    ) versus
    defineContract({ extensionPacks: { pgvector } })
    (record of pack descriptors from
    @prisma-next/extension-<name>/pack
    ). The
    PN-CLI-4011
    envelope's fix text refers to
    extensions
    — that field name matches the façade.
  6. Renaming a field and expecting the planner to detect it. Prisma Next has no in-contract rename hint; the planner sees a destructive drop+add. Hand-edit
    migration.ts
    after
    migration plan
    (see
    prisma-next-migrations
    ), or use the keep-then-drop two-migration pattern.
  1. 编辑后忘记重新生成
    contract.json
    contract.d.ts
    会过期;下游类型检查和
    migration plan
    会看到旧结构。请重新生成,或安装Vite插件(
    prisma-next-build
    )。
  2. 编辑生成产物
    contract.json
    contract.d.ts
    是生成文件;对它们的修改会在下一次生成时被覆盖。请编辑源文件。
  3. TS构建器使用错误的工厂/导入路径
    defineContract
    field
    model
    rel
    来自
    @prisma-next/postgres/contract-builder
    (或
    @prisma-next/mongo/contract-builder
    )。回调重载外可用的字段构造器只有
    field.column(...)
    field.generated(...)
    field.namedType(...)
  4. 从用户代码中导入内部包:用户编写的文件(
    prisma-next.config.ts
    contract.ts
    db.ts
    、控制客户端)只能从
    @prisma-next/<target>/<subpath>
    @prisma-next/extension-<name>/<subpath>
    导入。从
    @prisma-next/cli/*
    @prisma-next/family-*
    @prisma-next/target-*
    @prisma-next/adapter-*
    @prisma-next/driver-*
    @prisma-next/sql-contract-*
    导入属于框架内部操作——外观已为你组合好这些内容。如果你的目标缺少所需的外观子路径,请查看「Prisma Next暂不支持的功能」并引导至
    prisma-next-feedback
    (跟踪ID:TML-2526)。标准示例见
    examples/multi-extension-monorepo/app/prisma-next.config.ts
    examples/cipherstash-integration/prisma-next.config.ts
    examples/prisma-next-postgis-demo/prisma-next.config.ts
  5. 混淆
    extensions
    (配置外观)和
    extensionPacks
    (TS构建器)
    :相同的包,不同的交互层,不同的字段名称:
    defineConfig({ extensions: [pgvector] })
    (从
    @prisma-next/extension-<name>/control
    导入的控制描述符数组) vs
    defineContract({ extensionPacks: { pgvector } })
    (从
    @prisma-next/extension-<name>/pack
    导入的描述符对象)。
    PN-CLI-4011
    错误信息的修复文本提到的
    extensions
    是外观中的字段名称。
  6. 重命名字段后期望规划器自动检测:Prisma Next没有契约内重命名提示;规划器会将其视为破坏性的删除+添加操作。在
    migration plan
    后手动编辑
    migration.ts
    (详见
    prisma-next-migrations
    ),或使用保留后删除的两步迁移模式。

What Prisma Next doesn't do yet

Prisma Next暂不支持的功能

  • Mongo config façade is narrower than Postgres.
    @prisma-next/mongo/config
    's
    defineConfig
    accepts only
    contract
    and
    db
    ; there's no
    extensions
    field and no
    migrations.dir
    field. Track via TML-2526; file additional gaps via
    prisma-next-feedback
    .
  • SQLite has no
    /config
    or
    /contract-builder
    façade subpath.
    @prisma-next/sqlite
    exposes only
    /runtime
    . There is no façade-shaped way to author SQLite config or TS contracts today. Track via TML-2526; if you hit this, route via
    prisma-next-feedback
    .
  • In-contract rename hint. No
    @@rename(old: ..., new: ...)
    or similar. Use the workarounds in Common Pitfalls #6. To request first-class rename, file via
    prisma-next-feedback
    .
  • Model validations. No declarative
    @validates(...)
    surface. Validate in application code (arktype). To request declarative validations in the contract, file via
    prisma-next-feedback
    .
  • Lifecycle callbacks (
    beforeSave
    ,
    afterCreate
    , etc.). Not supported. Use middleware (
    prisma-next-runtime
    ) or app code. To request lifecycle callbacks, file via
    prisma-next-feedback
    .
  • Soft delete /
    paranoid: true
    .
    No built-in soft-delete column. Add a nullable
    deletedAt DateTime?
    and filter explicitly in queries (or in middleware). To request built-in soft delete, file via
    prisma-next-feedback
    .
  • Scopes / default filters. No ActiveRecord-style scopes. Compose query helpers yourself. To request scopes, file via
    prisma-next-feedback
    .
  • Composite / embeddable types on SQL. PSL parses
    type Foo { ... }
    syntax but the SQL interpreter does not lower it to composite types or JSON columns. Use a separate model + relation, or a
    Json
    column with application-side schemas. To request first-class composite types, file via
    prisma-next-feedback
    .
  • Implicit Prisma-ORM many-to-many. List navigation on both sides without an explicit join model is rejected. Author the join model explicitly. To request implicit M2M, file via
    prisma-next-feedback
    .
  • Mongo配置外观比Postgres更受限
    @prisma-next/mongo/config
    defineConfig
    仅接受
    contract
    db
    ;没有
    extensions
    字段和
    migrations.dir
    字段。跟踪ID:TML-2526;如有其他缺失功能,请通过
    prisma-next-feedback
    提交。
  • SQLite没有
    /config
    /contract-builder
    外观子路径
    @prisma-next/sqlite
    仅暴露
    /runtime
    。目前没有外观化的方式编写SQLite配置或TS契约。跟踪ID:TML-2526;如遇到此问题,请引导至
    prisma-next-feedback
  • 契约内重命名提示:没有
    @@rename(old: ..., new: ...)
    或类似功能。请使用「常见陷阱」第6条中的解决方法。如需原生重命名功能,请通过
    prisma-next-feedback
    提交请求。
  • 模型验证:没有声明式
    @validates(...)
    交互层。请在应用代码中验证(如arktype)。如需在契约中添加声明式验证,请通过
    prisma-next-feedback
    提交请求。
  • 生命周期回调
    beforeSave
    afterCreate
    等):不支持。请使用中间件(
    prisma-next-runtime
    )或应用代码。如需生命周期回调,请通过
    prisma-next-feedback
    提交请求。
  • 软删除 /
    paranoid: true
    :没有内置软删除列。请添加可空的
    deletedAt DateTime?
    并在查询中显式过滤(或在中间件中处理)。如需内置软删除功能,请通过
    prisma-next-feedback
    提交请求。
  • 作用域 / 默认过滤器:没有ActiveRecord风格的作用域。请自行组合查询辅助函数。如需作用域功能,请通过
    prisma-next-feedback
    提交请求。
  • SQL上的组合/可嵌入类型:PSL会解析
    type Foo { ... }
    语法,但SQL解释器不会将其转换为组合类型或JSON列。请使用单独的模型+关联关系,或带应用端Schema的
    Json
    列。如需原生组合类型,请通过
    prisma-next-feedback
    提交请求。
  • 隐式Prisma-ORM多对多:两端都有列表导航但无显式连接模型会被拒绝。请显式编写连接模型。如需隐式多对多功能,请通过
    prisma-next-feedback
    提交请求。

Reference

参考资料

  • Run
    pnpm prisma-next contract --help
    for the live command surface.
  • PSL feature surface and what the interpreter accepts:
    packages/2-sql/2-authoring/contract-psl/README.md
    .
  • TS builder surface and the callback-helper vocabulary:
    packages/2-sql/2-authoring/contract-ts/README.md
    .
  • Layouts (where
    contract.prisma
    ,
    contract.json
    ,
    contract.d.ts
    , and
    migrations/
    live):
    • App layout (
      src/prisma/...
      +
      migrations/app/...
      ) — what
      examples/prisma-next-demo
      demonstrates; the canonical shape consuming applications use.
    • Contract-space-package layout (
      src/contract.{prisma,ts}
      directly,
      migrations/<timestamp>_<slug>/
      without a space-id segment) — for extensions and aggregate-root packages, documented in
      .cursor/rules/contract-space-package-layout.mdc
      and ADR 212.
  • 运行
    pnpm prisma-next contract --help
    查看实时命令交互层。
  • PSL功能交互层和解释器支持的内容:
    packages/2-sql/2-authoring/contract-psl/README.md
  • TS构建器交互层和回调辅助函数词汇:
    packages/2-sql/2-authoring/contract-ts/README.md
  • 布局(
    contract.prisma
    contract.json
    contract.d.ts
    migrations/
    的位置):
    • 应用布局
      src/prisma/...
      +
      migrations/app/...
      )——
      examples/prisma-next-demo
      演示的布局;消费应用使用的标准结构。
    • 契约空间包布局(直接在
      src/contract.{prisma,ts}
      migrations/<timestamp>_<slug>/
      无空间ID段)——适用于扩展和聚合根包,文档见
      .cursor/rules/contract-space-package-layout.mdc
      和ADR 212。

Checklist

检查清单

  • Read
    prisma-next.config.ts
    and identified the contract source (path string ending in
    .prisma
    or
    .ts
    ) and the installed
    extensions: [...]
    .
  • All user-authored imports resolve to
    @prisma-next/<target>/<subpath>
    (e.g.
    @prisma-next/postgres/config
    ) or
    @prisma-next/extension-<name>/<subpath>
    . No imports from
    @prisma-next/cli/*
    ,
    @prisma-next/family-*
    ,
    @prisma-next/target-*
    ,
    @prisma-next/adapter-*
    ,
    @prisma-next/driver-*
    , or
    @prisma-next/sql-contract-*
    in user files.
  • Edited the contract source (
    contract.prisma
    or
    contract.ts
    ), not an emitted artefact.
  • For new extension namespaces: added the package, imported its control descriptor (
    @prisma-next/extension-<name>/control
    ), added it to
    extensions: [...]
    in
    defineConfig({...})
    (and the matching pack descriptor to
    defineContract({extensionPacks: {...}})
    if using the TS builder).
  • For renames: hand-edited
    migration.ts
    after
    migration plan
    (or used the keep-then-drop two-migration pattern) — Prisma Next has no rename hint today.
  • Ran
    pnpm prisma-next contract emit
    after the edit (or let the Vite plugin re-emit on save).
  • Confirmed
    contract.json
    and
    contract.d.ts
    updated next to the source.
  • Did not hand-edit
    contract.json
    /
    contract.d.ts
    .
  • Did not confabulate a missing feature (validations, callbacks, soft delete, scopes, in-contract rename hint, composite types) — referred the user to What Prisma Next doesn't do yet +
    prisma-next-feedback
    .
  • 已读取
    prisma-next.config.ts
    并确定契约源文件(以
    .prisma
    .ts
    结尾的路径字符串)和已安装的
    extensions: [...]
  • 所有用户编写的导入都指向
    @prisma-next/<target>/<subpath>
    (如
    @prisma-next/postgres/config
    )或
    @prisma-next/extension-<name>/<subpath>
    。用户文件中没有从
    @prisma-next/cli/*
    @prisma-next/family-*
    @prisma-next/target-*
    @prisma-next/adapter-*
    @prisma-next/driver-*
    @prisma-next/sql-contract-*
    导入的内容。
  • 已编辑契约源文件(
    contract.prisma
    contract.ts
    ),而非生成产物。
  • 对于新的扩展命名空间:已安装对应包,导入其控制描述符(
    @prisma-next/extension-<name>/control
    ),添加到
    defineConfig({...})
    extensions: [...]
    中(如果使用TS构建器,还需将匹配的包描述符添加到
    defineContract({extensionPacks: {...}})
    )。
  • 对于重命名操作:在
    migration plan
    后手动编辑
    migration.ts
    (或使用保留后删除的两步迁移模式)——Prisma Next目前没有重命名提示。
  • 编辑后已运行
    pnpm prisma-next contract emit
    (或让Vite插件在保存时自动重新生成)。
  • 已确认
    contract.json
    contract.d.ts
    在源文件旁更新。
  • 手动编辑
    contract.json
    /
    contract.d.ts
  • 虚构缺失功能(验证、回调、软删除、作用域、契约内重命名提示、组合类型)——已引导用户查看「Prisma Next暂不支持的功能」+
    prisma-next-feedback