6 Commits

Author SHA1 Message Date
R524809 69ec885803 feat: 数据库导出文档 2026-10-20 17:29:10 +08:00
R524809 48c45ada89 feat: 部署准备 2026-10-19 17:48:57 +08:00
R524809 d30cf25890 feat: 完成现有小程序接口的全部迁移至新后端 2026-10-19 13:17:51 +08:00
R524809 8827110f2f feat: 完成分类、worksheet 接口开发,资源迁移到七牛 2026-10-16 17:32:23 +08:00
R524809 e6ded00a4c docs: 基本完成初版数据库设计 2026-10-15 10:09:34 +08:00
R524809 63a6993276 feat: 创建数据库 2026-10-12 16:56:42 +08:00
266 changed files with 32003 additions and 446 deletions
+1 -1
View File
@@ -4,6 +4,6 @@ root = true
charset = utf-8 charset = utf-8
end_of_line = lf end_of_line = lf
indent_style = space indent_style = space
indent_size = 2 indent_size = 4
insert_final_newline = true insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true
+6
View File
@@ -0,0 +1,6 @@
# 仅用于本地 Docker Compose,命令从 doodle-store 根目录执行。
POSTGRES_PORT=5434
POSTGRES_DB=doodle_dev
POSTGRES_USER=doodle_dev
# 本地开发专用;复制为 .env 后替换,真实密码不要提交仓库。
POSTGRES_PASSWORD=change-me-local-only
+1
View File
@@ -5,6 +5,7 @@ dist-test/
coverage/ coverage/
*.tsbuildinfo *.tsbuildinfo
*.log *.log
/apps/server/src/generated/
.DS_Store .DS_Store
.env .env
.env.* .env.*
+3
View File
@@ -4,3 +4,6 @@ dist
dist-test dist-test
coverage coverage
pnpm-lock.yaml pnpm-lock.yaml
apps/server/src/generated
packages/asset-sync/reports
+4 -2
View File
@@ -1,4 +1,6 @@
{ {
"singleQuote": true, "tabWidth": 4,
"trailingComma": "all" "useTabs": false,
"singleQuote": true,
"trailingComma": "all"
} }
+6
View File
@@ -0,0 +1,6 @@
# 项目编码约定
- 使用 4 个空格缩进,不使用 Tab;遵循项目 EditorConfig 与 Prettier 配置。
- 新增或修改代码时添加适当的中文注释。公共类、服务方法和接入接口说明职责与使用前提;复杂逻辑说明设计原因、处理顺序、边界条件及异常行为。
- 配置校验、鉴权与权限、事务与幂等、第三方服务接入、日志脱敏等关键逻辑应有注释。临时占位实现要说明当前行为和后续替换位置。
- 注释保持简洁,避免逐行复述代码或给显而易见的操作添加无意义注释;修改逻辑时同步更新相关注释。
+68 -5
View File
@@ -1,18 +1,23 @@
# Doodle Store # Doodle Store
当前进度、旧线上服务保留约束、验证结果及下一步任务见 [开发交接文档](docs/v3.5/开发交接文档.md)(2026-10-19)。
独立于 `doodle-mini` 的 pnpm Monorepo,用于维护统一业务后端、后续管理后台和用户 Web 网站。小程序源码与 CloudBase 兼容函数仍在 `doodle-mini`,两个项目通过 HTTPS API 协作。 独立于 `doodle-mini` 的 pnpm Monorepo,用于维护统一业务后端、后续管理后台和用户 Web 网站。小程序源码与 CloudBase 兼容函数仍在 `doodle-mini`,两个项目通过 HTTPS API 协作。
## 当前范围 ## 当前范围
本次仅初始化工程,不开发具体业务: 当前已完成基础工程、本地数据库、小程序登录鉴权及分类服务:
- `apps/server`:可运行的 NestJS 服务,只有进程健康检查。 - `apps/server`:可运行的 NestJS 服务,已接入日志、中间件、Swagger、微信静默登录、JWT 与真实账户检查,提供本人摘要、分类查询/管理、题型列表/详情与组合筛选和数据库就绪接口。
- `packages/contracts`:基础成功响应与健康检查类型,不包含业务字段或私有实现。 - `packages/contracts`:公开响应、登录请求/结果、本人摘要、分类与安全错误类型,不包含数据库模型或私有实现。
- `packages/asset-sync`:本地云存储备份同步七牛的独立 Node.js 工具,支持预演、校验、重试,头像与其他资源共用公开空间。
- `apps/admin`、`apps/web`:仅预留目录与说明,尚未选择或安装前端框架。 - `apps/admin`、`apps/web`:仅预留目录与说明,尚未选择或安装前端框架。
- 数据库、Prisma、微信登录、七牛、定时任务、业务接口与生产部署尚未接入。 - 本地 PostgreSQL 18.6 Docker 开发环境已启动,13 张表及初始配置已创建,并于 2026-10-15 与最新 SQL 复核一致;Prisma 与微信登录已接入,七牛、其他业务及生产部署待实施。
## 本地使用 ## 本地使用
先按 [本地数据库说明](infra/README.md) 配置根 `.env`,执行 `pnpm infra:up`。默认数据库地址为 `127.0.0.1:5434`,开发库为 `doodle_dev`。图片等资源直接使用七牛,本地仅启动 PostgreSQL。生产与按需测试的安排见 [v3.5 开发与部署环境方案](docs/v3.5/开发与部署环境方案.md)。
使用 Node.js **24.20.0** 与 pnpm **11.24.0**。如使用 fnm,可在本目录执行 `fnm use --install-if-missing`。 使用 Node.js **24.20.0** 与 pnpm **11.24.0**。如使用 fnm,可在本目录执行 `fnm use --install-if-missing`。
```bash ```bash
@@ -21,12 +26,19 @@ pnpm build
pnpm dev pnpm dev
``` ```
默认地址为 `http://127.0.0.1:3000/api/v1/health`。该接口只证明服务进程可以处理 HTTP 请求,不代表数据库、文件存储或业务系统已经可用。 默认地址为 `http://127.0.0.1:8800/api/v1/health`。该接口只证明服务进程可以处理 HTTP 请求,不代表数据库、文件存储或业务系统已经可用。
`pnpm dev` 在服务监听成功后显示完整 Swagger 地址(默认 `http://127.0.0.1:8800/api-docs`),并使用系统默认浏览器自动打开一次。热更新不会重复打开;关闭 Swagger 时不打开。链接按实际 HOST/PORT 生成,建议使用输出的 IP 地址,避免 `localhost` 解析到其他项目。
可在 `apps/server/.env` 中配置 `PORT`、`HOST`,变量示例见 `apps/server/.env.example`。未配置时使用安全的本地默认值。不要提交真实 `.env` 或密钥。 可在 `apps/server/.env` 中配置 `PORT`、`HOST`,变量示例见 `apps/server/.env.example`。未配置时使用安全的本地默认值。不要提交真实 `.env` 或密钥。
JWT_SECRET 必须配置为至少 32 字节的独立密钥,本机开发密钥已生成。Swagger 默认开发开启:`http://127.0.0.1:8800/api-docs`,生产未显式配置时关闭;其他设置与账户查询接入边界见 [Server 基础设置](docs/v3.5/Server基础设置.md)。
微信小程序配置在 `apps/server/.env` 中填写 `WECHAT_MINI_APP_ID` 和 `WECHAT_MINI_APP_SECRET`。两项均为启动必填;DATABASE_URL 同样必须配置。真实 AppSecret 仅由服务端持有,不提交仓库。
```bash ```bash
pnpm check # 格式、代码检查、类型检查、构建与测试 pnpm check # 格式、代码检查、类型检查、构建与测试
pnpm test:db # 独立临时数据库中的登录/鉴权/分类测试,结束后清理
pnpm build # 按工作区依赖顺序构建 pnpm build # 按工作区依赖顺序构建
pnpm start # 运行已构建的服务端 pnpm start # 运行已构建的服务端
pnpm format # 格式化源码与配置 pnpm format # 格式化源码与配置
@@ -40,8 +52,10 @@ apps/
admin/ 后续管理后台,当前仅占位 admin/ 后续管理后台,当前仅占位
web/ 后续用户网站,当前仅占位 web/ 后续用户网站,当前仅占位
packages/ packages/
asset-sync/ 云存储备份同步七牛的独立脚本
contracts/ 可公开的接口类型 contracts/ 可公开的接口类型
deploy/ 后续部署说明,当前未部署 deploy/ 后续部署说明,当前未部署
infra/ 本地 PostgreSQL Docker 配置
docs/ 工程初始化与接入边界说明 docs/ 工程初始化与接入边界说明
``` ```
@@ -49,4 +63,53 @@ docs/ 工程初始化与接入边界说明
数据库模型、密钥和未来私有生成/绘制逻辑只能由服务端持有,不能放进公共契约包供前端导入。小程序不直接依赖本仓库源码或本地工作区包。 数据库模型、密钥和未来私有生成/绘制逻辑只能由服务端持有,不能放进公共契约包供前端导入。小程序不直接依赖本仓库源码或本地工作区包。
登录请求、恢复错误码、数据库基线及联调边界见 [服务端登录接入说明](docs/v3.5/服务端登录接入说明.md)。
分类公开/管理 API、本地导入工具及本批 6 条分类的导入结果见 [分类接口与数据导入](docs/v3.5/分类接口与数据导入.md)。
51 条旧题型数据已导入本地库,预览文件仍待迁移;导入工具、异常年级和计数对账见 [题型数据导入说明](docs/v3.5/题型数据导入说明.md)。
题型查询支持分类、审核年级、年龄段、Tag、最新/热门、运营标记和分页,见 [题型查询接口说明](docs/v3.5/题型查询接口说明.md)。
现有功能迁移的权威方案见 [docs/云服务端迁移方案.md](docs/云服务端迁移方案.md),小程序产品规划与历史设计仍保留在 `doodle-mini`。本仓库的初始化说明见 [docs/初始化说明.md](docs/初始化说明.md)。 现有功能迁移的权威方案见 [docs/云服务端迁移方案.md](docs/云服务端迁移方案.md),小程序产品规划与历史设计仍保留在 `doodle-mini`。本仓库的初始化说明见 [docs/初始化说明.md](docs/初始化说明.md)。
## 云存储备份同步七牛
独立脚本项目位于 [packages/asset-sync](packages/asset-sync/README.md),配置入口为该目录的 `.env`,已填写本地 cloud_backup 源目录。`pnpm assets:sync` 默认只预演;填写七牛 AK/SK 与 bucket 后,使用 `pnpm assets:sync --apply --only assets/previews` 同步题型预览。支持保留相对路径、同内容跳过、冲突保护、有限重试和报告;头像与其他资源共用 QINIU_BUCKET 公开空间。该工具不修改业务数据库或自动替换旧 cloud 引用。
### 服务端资源地址配置
`apps/server/.env` 与 asset-sync 使用同一组公开配置;服务端无需配置七牛 AK/SK:
```dotenv
QINIU_PUBLIC_DOMAIN=https://cdn.joeyone.cn
QINIU_KEY_PREFIX=doodle-assets/
QINIU_BUCKET=doodle-cn
```
地址规则为「域名 / 对象 key」。字体等固定资源由 `publicResourceUrl(config, 'assets/fonts/ToneOZ-Pinyin-Regular.ttf')` 补上前缀,得到 `https://cdn.joeyone.cn/doodle-assets/assets/fonts/ToneOZ-Pinyin-Regular.ttf`。支持空前缀;域名仅接受 HTTPS origin,不包含目录。修改配置后重启 server。
数据库 `assets.object_key` 存完整 key,例如 `doodle-assets/assets/previews/math/example.jpg`,返回预览时直接拼域名,不再次添加前缀。`QINIU_BUCKET` 是对象所属空间,不拼进 URL,也不会自动修改资产记录。图片上传成功后仍需根据同步报告回填资产的 key、bucket、摘要等字段并标记 ready;pending 资产继续返回空预览,配置域名不会自动宣布迁移完成。
资源上传后,可将成功同步报告映射回本地 `assets`,保留原资源 ID 与业务表外键:
```bash
# 预演:重新核对本地文件与七牛对象,仅允许本机 doodle_dev
pnpm assets:map --report /绝对路径/成功同步报告.json
# 核对通过后,整批事务写入并记录迁移审计
pnpm assets:map --report /绝对路径/成功同步报告.json --apply
```
当前工具处理已有 cloud 来源的题型预览:根据原文件相对路径匹配,回填 bucket、完整 objectKey、MIME、大小和 SHA-256,设置 ready。重复执行同一映射会跳过,已就绪但映射不同的资产会拒绝覆盖;有缺失或核对失败则整批不写入。不创建用户头像记录、不猜测头像归属。
业务表(例如 worksheets.preview_asset_id、users.avatar_asset_id)仅保存资源 ID;assets 保存文件定位和元数据,不保存七牛完整访问 URL。固定字体未作为业务记录入库,小程序通过 `miniprogram/config/assets.ts` 统一配置域名和前缀;接口提供的图片地址直接使用,不在小程序重复拼接。
### 微信登录上游失败排查
`503 / AUTH_UPSTREAM_UNAVAILABLE` 表示服务端兑换微信 code 未成功。查看同一 requestId 的 `wechat_exchange_failed` 日志:只记录失败阶段、HTTP 状态和微信数值错误码,不输出 AppSecret、code、完整请求 URL 或微信 errmsg。
若 `wechat_errcode=40164`,且有 `egress_ip`,表示微信拒绝当前服务器公网出口 IP。登录对应 AppID 的微信公众平台,在服务端接口调用的 IP 白名单中添加该出口 IP(与代码上传白名单分别核对),保存后在小程序重新触发登录。换网络或代理出口后需重新核对 IP;上线时使用实际服务器的固定出口 IP。仅修改本站后端 `.env` 无法解除微信侧白名单限制。
### 小程序业务接口迁移
除微信预拉取外,用户资料、头像、收藏、下载记录、年龄推荐、动态首页兜底和各管理页已迁至本站 API;详见 [小程序云接口迁移清单](docs/v3.5/小程序云接口迁移清单.md)。上传凭据仅由服务端持有,本地已沿用 asset-sync 的七牛配置。`20261019000000_member_assets` 已在本地应用;云端历史用户及关联记录仍需单独导入。管理功能要求数据库当前角色为 admin,不自动授权开发者账户。
@@ -0,0 +1,267 @@
---
name: prisma-cli
description: Prisma ORM 7 CLI reference for existing Prisma 7 applications or explicitly selected Prisma 7 workflows. Covers prisma init, generate, migrate, db, dev, studio, and mcp. For setup, connection repair, or Prisma 8, use prisma-orm-setup; not the Prisma Platform CLI.
license: MIT
metadata:
author: prisma
version: "7.9.1"
---
# Prisma ORM 7 CLI reference
These commands and examples apply to **Prisma ORM 7** only. For setup, connection repair, or a Prisma 8 application, load [prisma-orm-setup](../prisma-orm-setup/SKILL.md).
Use the project's version-matched CLI. Do not install a floating `prisma@latest` to run these commands.
## Boundary: Platform and Compute
Do not confuse the stable ORM command (`prisma`) with the public-beta Platform package (`@prisma/cli`, binary `prisma-cli`). Use `prisma-compute` for Compute apps and workspace auth, and `prisma-postgres-setup` for Platform projects and databases.
## When to Apply
Reference this skill when:
- Setting up an explicitly selected Prisma 7 project (`prisma init`)
- Generating Prisma Client (`prisma generate`)
- Running database migrations (`prisma migrate`)
- Managing database state (`prisma db push/pull`)
- Using local development database (`prisma dev`)
- Debugging Prisma issues (`prisma debug`)
- Generating shell completions (`prisma complete`)
## Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | Setup | HIGH | `init` |
| 2 | Generation | HIGH | `generate` |
| 3 | Development | HIGH | `dev` |
| 4 | Database | HIGH | `db-` |
| 5 | Migrations | CRITICAL | `migrate-` |
| 6 | Utility | MEDIUM | `complete`, `studio`, `validate`, `format`, `debug`, `mcp` |
## Command Categories
| Category | Commands | Purpose |
|----------|----------|---------|
| Setup | `init` | Initialize a Prisma project |
| Generation | `generate` | Generate Prisma Client |
| Validation | `validate`, `format` | Schema validation and formatting |
| Development | `dev` | Local Prisma Postgres for development |
| Database | `db pull`, `db push`, `db seed`, `db execute` | Direct database operations |
| Migrations | `migrate dev`, `migrate deploy`, `migrate reset`, `migrate status`, `migrate diff`, `migrate resolve` | Schema migrations |
| Utility | `complete`, `studio`, `mcp`, `version`, `debug` | Shell, development, and AI tooling |
## Quick Reference
### Project Setup
```bash
# Initialize new project (creates prisma/ folder and prisma.config.ts)
prisma init
# Initialize with specific database
prisma init --datasource-provider postgresql
prisma init --datasource-provider mysql
prisma init --datasource-provider sqlite
# Initialize with Prisma Postgres (cloud)
prisma init --db
# Initialize with an example model
prisma init --with-model
```
### Client Generation
```bash
# Generate Prisma Client
prisma generate
# Watch mode for development
prisma generate --watch
# Generate specific generator only
prisma generate --generator client
```
### Bun Runtime
When using Bun, always add the `--bun` flag so Prisma runs with the Bun runtime (otherwise it falls back to Node.js because of the CLI shebang):
```bash
bunx --bun prisma init
bunx --bun prisma generate
```
### Local Development Database
```bash
# Start local Prisma Postgres
prisma dev
# Start with specific name
prisma dev --name myproject
# Start in background (detached)
prisma dev --detach
# List all local instances
prisma dev ls
# Stop instance
prisma dev stop myproject
# Remove instance data
prisma dev rm myproject
```
### Database Operations
```bash
# Pull schema from existing database
prisma db pull
# Push schema to database (no migrations)
prisma db push
# Seed database
prisma db seed
# Execute raw SQL
prisma db execute --file ./script.sql
```
### Migrations (Development)
```bash
# Create and apply migration
prisma migrate dev
# Create migration with name
prisma migrate dev --name add_users_table
# Create migration without applying
prisma migrate dev --create-only
# Reset database and apply all migrations
prisma migrate reset
```
### Migrations (Production)
```bash
# Apply pending migrations (CI/CD)
prisma migrate deploy
# Check migration status
prisma migrate status
# Compare schemas and generate diff
prisma migrate diff --from-config-datasource --to-schema schema.prisma --script
```
### Utility Commands
```bash
# Open Prisma Studio (database GUI)
prisma studio
# Start Prisma's MCP server for AI tools
prisma mcp
# Show version info
prisma version
prisma -v
# Debug information
prisma debug
# Validate schema
prisma validate
# Format schema
prisma format
# Generate shell completion code
prisma complete zsh
```
## AI Safety Checkpoint
Prisma blocks destructive commands when it detects an AI agent until the agent has obtained explicit user consent. This covers `migrate reset`, `db push --force-reset`, and `db push --accept-data-loss`.
- Explain the exact data-loss impact and ask for consent immediately before running the command.
- Do not infer consent from earlier or unrelated messages.
- If automation needs the consent variable, set `PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION` to the user's exact consent message. Do not invent the text.
- The Prisma MCP server deliberately has no `migrate-reset` tool.
Read `references/agent-safety.md` before any destructive Prisma command.
## Current Prisma CLI Setup
### New Configuration File
Use `prisma.config.ts` for CLI configuration:
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
seed: 'tsx prisma/seed.ts',
},
datasource: {
url: env('DATABASE_URL'),
},
})
```
### Current Command Behavior
- Run `prisma generate` explicitly after `migrate dev`, `db push`, or other schema syncs when you need fresh client output
- Run `prisma db seed` explicitly after `migrate dev` or `migrate reset` when you need seed data
- Use `prisma db execute --file ...` for raw SQL scripts
### Environment Variables
Load environment variables explicitly in `prisma.config.ts`, commonly with `dotenv`:
```typescript
// prisma.config.ts
import 'dotenv/config'
```
## Rule Files
See individual rule files for detailed command documentation:
```
references/init.md - Project initialization
references/generate.md - Client generation
references/dev.md - Local development database
references/db-pull.md - Database introspection
references/db-push.md - Schema push
references/db-seed.md - Database seeding
references/db-execute.md - Raw SQL execution
references/migrate-dev.md - Development migrations
references/migrate-deploy.md - Production migrations
references/migrate-reset.md - Database reset
references/migrate-status.md - Migration status
references/migrate-resolve.md - Migration resolution
references/migrate-diff.md - Schema diffing
references/studio.md - Database GUI
references/mcp.md - Prisma MCP server
references/complete.md - Shell completion generation
references/agent-safety.md - AI consent checkpoint for destructive commands
references/validate.md - Schema validation
references/format.md - Schema formatting
references/debug.md - Debug info
```
## How to Use
Use the command categories above for navigation, then open the specific command reference file you need.
@@ -0,0 +1,27 @@
# AI safety checkpoint for destructive commands
Prisma detects common AI-agent environments and blocks these commands until the user gives explicit consent:
- `prisma migrate reset`
- `prisma db push --force-reset`
- `prisma db push --accept-data-loss`
## Required workflow
1. Inspect the target database/config and explain exactly what can be deleted or reset.
2. Ask the user for explicit consent immediately before the action.
3. Run the command only after that consent.
For an agent-run subprocess, Prisma accepts the exact consent text through:
```bash
PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION='<exact user consent message>' prisma migrate reset --force
```
The value must match the user's message exactly and must not contain added quotes or newlines. Never fabricate consent, reuse an old unrelated approval, or bypass the checkpoint by hiding agent-detection environment variables.
The MCP server has no `migrate-reset` tool. Use the shell command only after consent.
## Reference
- [Prisma ORM 7.9.0 release](https://github.com/prisma/prisma/releases/tag/7.9.0)
@@ -0,0 +1,22 @@
# prisma complete
Prints a shell completion script.
```bash
prisma complete zsh
prisma complete bash
prisma complete fish
prisma complete powershell
```
For a direct global CLI installation, load the output using the shell's normal startup mechanism. For example, in zsh:
```bash
source <(prisma complete zsh)
```
Prisma also integrates with supported package-manager completion flows. `npx` and `bunx` do not themselves provide completion; invoke the installed binary or the package manager's supported execution form such as `npm exec` or `bun x`.
## Reference
- [Prisma ORM 7.9.0 release](https://github.com/prisma/prisma/releases/tag/7.9.0)
@@ -0,0 +1,78 @@
# prisma db execute
Execute native commands (SQL) to your database.
## Command
```bash
prisma db execute [options]
```
## What It Does
- Connects to your database using the configured datasource
- Executes a script provided via file (`--file`) or stdin (`--stdin`)
- Useful for running raw SQL, maintenance tasks, or applying diffs from `migrate diff`
- Not supported on MongoDB
## Options
| Option | Description |
|--------|-------------|
| `--file` | Path to a file containing the script to execute |
| `--stdin` | Use terminal standard input as the script |
| `--config` | Custom path to your Prisma config file |
## Current Option Surface
`prisma db execute` uses the datasource configured in `prisma.config.ts`. Use `--config` if you need a separate config file for another environment.
## Examples
### Execute from file
```bash
prisma db execute --file ./script.sql
```
### Execute from stdin
```bash
echo "TRUNCATE TABLE User;" | prisma db execute --stdin
```
### Execute `migrate diff` output
Pipe the output of `migrate diff` directly to the database:
```bash
prisma migrate diff \
--from-empty \
--to-schema prisma/schema.prisma \
--script \
| prisma db execute --stdin
```
## Configuration
Uses `datasource` from `prisma.config.ts`:
```typescript
export default defineConfig({
datasource: {
url: env('DATABASE_URL'),
},
})
```
## Use Cases
- **Manual Migrations**: Applying raw SQL changes
- **Data Maintenance**: Truncating tables, cleaning up data
- **Schema Synchronization**: Applying `migrate diff` scripts
- **Debugging**: Running test queries (though typically not for fetching data)
## Limitations
- **No Data Return**: The command reports success/failure, not query results (rows). Use Prisma Client or `prisma studio` to view data.
- **SQL Only**: Primarily for SQL databases.
@@ -0,0 +1,185 @@
# prisma db pull
Introspects an existing database and updates your Prisma schema to reflect its structure.
## Command
```bash
prisma db pull [options]
```
## What It Does
- Connects to your database
- Reads the database schema (tables, columns, relations, indexes)
- Updates `schema.prisma` with corresponding Prisma models
- For MongoDB, samples data to infer schema
## Options
| Option | Description |
|--------|-------------|
| `--force` | Ignore current Prisma schema file |
| `--print` | Print the introspected Prisma schema to stdout |
| `--schema` | Custom path to your Prisma schema |
| `--config` | Custom path to your Prisma config file |
| `--url` | Override the datasource URL from the Prisma config file |
| `--composite-type-depth` | Specify the depth for introspecting composite types (default: -1 for infinite, 0 = off) |
| `--schemas` | Specify the database schemas to introspect |
| `--local-d1` | Generate a Prisma schema from a local Cloudflare D1 database |
## Examples
### Basic introspection
```bash
prisma db pull
```
### Preview without writing
```bash
prisma db pull --print
```
Outputs schema to terminal for review.
### Force overwrite
```bash
prisma db pull --force
```
Replaces schema file, losing any manual customizations.
## Prerequisites
Configure database connection in `prisma.config.ts`:
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: env('DATABASE_URL'),
},
})
```
## Workflow
### Starting from existing database
1. Initialize Prisma:
```bash
prisma init
```
2. Configure database URL
3. Pull schema:
```bash
prisma db pull
```
4. Review and customize generated schema
5. Generate client:
```bash
prisma generate
```
### Syncing changes from database
When database changes are made outside Prisma:
```bash
prisma db pull
prisma generate
```
## Generated Schema Example
Database tables become Prisma models:
```sql
-- Database tables
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(100)
);
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
author_id INTEGER REFERENCES users(id)
);
```
Becomes:
```prisma
model users {
id Int @id @default(autoincrement())
email String @unique @db.VarChar(255)
name String? @db.VarChar(100)
posts posts[]
}
model posts {
id Int @id @default(autoincrement())
title String @db.VarChar(255)
author_id Int?
users users? @relation(fields: [author_id], references: [id])
}
```
## Post-Introspection Cleanup
After `db pull`, consider:
1. **Rename models** to PascalCase:
```prisma
model User { // Was: users
@@map("users")
}
```
2. **Rename fields** to camelCase:
```prisma
authorId Int? @map("author_id")
```
3. **Add relation names** for clarity:
```prisma
author User? @relation("PostAuthor", fields: [authorId], references: [id])
```
4. **Add documentation**:
```prisma
/// User account information
model User {
/// Primary email for authentication
email String @unique
}
```
## MongoDB Introspection
For MongoDB, `db pull` samples documents to infer schema:
```bash
prisma db pull
```
May require manual refinement since MongoDB is schemaless.
## Warning
`db pull` overwrites your schema file. Always:
- Commit current schema before pulling
- Use `--print` to preview first
- Backup customizations you want to keep
@@ -0,0 +1,150 @@
# prisma db push
Pushes schema changes directly to database without creating migrations. Ideal for prototyping.
## Command
```bash
prisma db push [options]
```
## What It Does
- Syncs your Prisma schema to the database
- Creates database if it doesn't exist
- Does NOT create migration files
- Does NOT track migration history
## Options
| Option | Description |
|--------|-------------|
| `--force-reset` | Force a reset of the database before push |
| `--accept-data-loss` | Ignore data loss warnings |
| `--schema` | Custom path to your Prisma schema |
| `--config` | Custom path to your Prisma config file |
| `--url` | Override the datasource URL from the Prisma config file |
When Prisma detects an AI agent, `--force-reset` and `--accept-data-loss` require explicit user consent. Follow `agent-safety.md`; never infer or fabricate the consent text.
### Follow-up Command
- Run `prisma generate` explicitly when you need refreshed client output
## Examples
### Basic push
```bash
prisma db push
```
### Accept data loss
```bash
prisma db push --accept-data-loss
```
Required when changes would delete data (dropping columns, etc.)
### Force reset
```bash
prisma db push --force-reset
```
Completely resets database and applies schema.
### Full workflow
```bash
prisma db push
prisma generate
```
## When to Use
- **Prototyping** - Rapid schema iteration
- **Local development** - Quick schema changes
- **MongoDB** - Primary workflow (migrations not supported)
- **Testing** - Setting up test databases
## When NOT to Use
- **Production** - Use `migrate deploy`
- **Team collaboration** - Use migrations for trackable changes
- **When you need rollback** - Migrations provide history
## Comparison with migrate dev
| Feature | db push | migrate dev |
|---------|---------|-------------|
| Creates migration files | No | Yes |
| Tracks history | No | Yes |
| Requires shadow database | No | Yes |
| Speed | Faster | Slower |
| Rollback capability | No | Yes |
| Best for | Prototyping | Development |
## MongoDB Workflow
MongoDB doesn't support migrations. Use `db push` exclusively:
```bash
# Schema changes for MongoDB
prisma db push
prisma generate
```
## Common Patterns
### Prototyping workflow
```bash
# Make schema changes
# ...
# Push to database
prisma db push
# Generate client
prisma generate
# Test your changes
# Repeat as needed
```
### Reset and start fresh
```bash
prisma db push --force-reset
prisma db seed
```
### Handling conflicts
If `db push` can't apply changes safely:
```
Error: The following changes cannot be applied:
- Removing field `email` would cause data loss
Use --accept-data-loss to proceed
```
Decide whether data loss is acceptable, then:
```bash
prisma db push --accept-data-loss
```
## Transition to Migrations
When ready for production, switch to migrations:
```bash
# Create baseline migration from current schema
prisma migrate dev --name init
```
Then use `migrate dev` for future changes.
@@ -0,0 +1,188 @@
# prisma db seed
Runs your database seed script to populate data.
## Command
```bash
prisma db seed [options]
```
## What It Does
- Executes your configured seed script
- Populates database with initial/test data
- Runs independently (not auto-run by migrations in v7)
## Options
| Option | Description |
|--------|-------------|
| `--config` | Custom path to your Prisma config file |
| `--` | Pass custom arguments to seed script |
## Configuration
Configure seed script in `prisma.config.ts`:
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
seed: 'tsx prisma/seed.ts', // Your seed command
},
datasource: {
url: env('DATABASE_URL'),
},
})
```
### Common seed commands
```typescript
// TypeScript with tsx
seed: 'tsx prisma/seed.ts'
// TypeScript with ts-node
seed: 'ts-node prisma/seed.ts'
// JavaScript
seed: 'node prisma/seed.js'
```
## Seed Script Example
```typescript
// prisma/seed.ts
import { PrismaClient } from '../generated/client'
const prisma = new PrismaClient()
async function main() {
// Create users
const alice = await prisma.user.upsert({
where: { email: 'alice@prisma.io' },
update: {},
create: {
email: 'alice@prisma.io',
name: 'Alice',
posts: {
create: {
title: 'Hello World',
published: true,
},
},
},
})
const bob = await prisma.user.upsert({
where: { email: 'bob@prisma.io' },
update: {},
create: {
email: 'bob@prisma.io',
name: 'Bob',
},
})
console.log({ alice, bob })
}
main()
.then(async () => {
await prisma.$disconnect()
})
.catch(async (e) => {
console.error(e)
await prisma.$disconnect()
process.exit(1)
})
```
## Examples
### Run seed
```bash
prisma db seed
```
### With custom arguments
```bash
prisma db seed -- --environment development
```
Arguments after `--` are passed to your seed script.
## Current Workflow
Run seeding explicitly after migrations when you need seed data:
```bash
prisma migrate dev --name init
prisma generate
prisma db seed # Must run explicitly
```
## Idempotent Seeding
Use `upsert` to make seeds re-runnable:
```typescript
// Good: Can run multiple times
await prisma.user.upsert({
where: { email: 'alice@prisma.io' },
update: {}, // Don't change existing
create: { email: 'alice@prisma.io', name: 'Alice' },
})
// Bad: Fails on second run
await prisma.user.create({
data: { email: 'alice@prisma.io', name: 'Alice' },
})
```
## Common Patterns
### Development reset
```bash
prisma migrate reset --force
prisma db seed
```
### Conditional seeding
```typescript
// prisma/seed.ts
const count = await prisma.user.count()
if (count === 0) {
// Only seed if empty
await seedUsers()
}
```
### Environment-specific seeds
```typescript
// prisma/seed.ts
const env = process.env.NODE_ENV || 'development'
if (env === 'development') {
await seedDevData()
} else if (env === 'test') {
await seedTestData()
}
```
## Best Practices
1. Use `upsert` for idempotent seeds
2. Keep seeds focused and minimal
3. Use realistic but fake data
4. Document required seed data
5. Version control your seed scripts
@@ -0,0 +1,46 @@
# prisma debug
Prints information helpful for debugging and bug reports.
## Command
```bash
prisma debug [options]
```
## What It Does
Outputs details about your Prisma environment, including:
- Prisma CLI version
- Prisma Client version (if installed)
- Engine binaries (Query Engine, Migration Engine, etc.)
- Platform information (OS, Architecture)
- Node.js version
- Configured datasource provider
## Options
| Option | Description |
|--------|-------------|
| `--schema` | Path to schema file |
| `--config` | Custom path to your Prisma config file |
## Example Output
```
prisma : 7.3.0
@prisma/client : 7.3.0
Operating System : darwin
Architecture : arm64
Node.js : v20.10.0
TypeScript : 5.3.3
Query Compiler : enabled
PSL : ...
Schema Engine : ...
```
## When to Use
- **Troubleshooting**: Checking version mismatches
- **Reporting Issues**: Including environment info in GitHub issues
- **Verifying Installation**: Ensuring correct binaries are downloaded
@@ -0,0 +1,157 @@
# prisma dev
Starts a local Prisma Postgres database for development. Provides a PostgreSQL-compatible database that runs entirely on your machine.
## Command
```bash
prisma dev [options]
```
## What It Does
- Starts a local PostgreSQL-compatible database
- Runs in your terminal or as a background process
- Perfect for development and testing
- Easy migration to Prisma Postgres cloud in production
## Options
| Option | Description | Default |
|--------|-------------|---------|
| `--name` / `-n` | Name for the database instance | `default` |
| `--port` / `-p` | HTTP server port | `51213` |
| `--db-port` / `-P` | Database server port | `51214` |
| `--shadow-db-port` | Shadow database port (for migrations) | `51215` |
| `--detach` / `-d` | Run in background | `false` |
| `--debug` | Enable debug logging | `false` |
## Examples
### Start local database
```bash
prisma dev
```
Interactive mode with keyboard shortcuts:
- `q` - Quit
- `h` - Show HTTP URL
- `t` - Show TCP URLs
### Named instance
```bash
prisma dev --name myproject
```
Useful for multiple projects.
### Background mode
```bash
prisma dev --detach
```
Frees your terminal for other commands.
### Custom ports
```bash
prisma dev --port 5000 --db-port 5432
```
## Instance Management
### List all instances
```bash
prisma dev ls
```
Shows all local Prisma Postgres instances with status.
### Start existing instance
```bash
prisma dev start myproject
```
Starts a previously created instance in background.
### Stop instance
```bash
prisma dev stop myproject
```
### Stop with glob pattern
```bash
prisma dev stop "myproject*"
```
Stops all instances matching pattern.
### Remove instance
```bash
prisma dev rm myproject
```
Removes instance data from filesystem.
### Force remove (stops first)
```bash
prisma dev rm myproject --force
```
## Configuration
Configure your `prisma.config.ts` to use local Prisma Postgres:
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
datasource: {
// Local Prisma Postgres URL (from prisma dev output)
url: env('DATABASE_URL'),
},
})
```
## Workflow
1. Start local database:
```bash
prisma dev
```
2. In another terminal, run migrations:
```bash
prisma migrate dev
```
3. Generate client:
```bash
prisma generate
```
4. Run your application
## Production Migration
When ready for production, switch to Prisma Postgres cloud:
```bash
prisma init --db
```
Update your `DATABASE_URL` to the cloud connection string.
@@ -0,0 +1,48 @@
# prisma format
Formats your Prisma schema file.
## Command
```bash
prisma format [options]
```
## What It Does
- Fixes formatting (indentation, spacing)
- Adds missing back-relations (e.g., adds the other side of a relation)
- Adds missing relation arguments (e.g., `fields`, `references`)
- Sorts fields and attributes (opinionated)
## Options
| Option | Description |
|--------|-------------|
| `--schema` | Path to schema file |
| `--config` | Custom path to your Prisma config file |
## Examples
### Format default schema
```bash
prisma format
```
### Format specific schema
```bash
prisma format --schema=./custom/schema.prisma
```
## Behavior
`prisma format` modifies the file in place. It is equivalent to "Prettier for Prisma schemas" but also has semantic understanding to fix/add missing schema definitions.
## Use in Editor
Most Prisma editor extensions (VS Code, WebStorm) run `prisma format` automatically on save. This command is useful for:
- CI pipelines (check formatting)
- CLI-based workflows
- Fixing large schema refactors
@@ -0,0 +1,173 @@
# prisma generate
Generates assets based on the generator blocks in your Prisma schema, most commonly Prisma Client.
## Command
```bash
prisma generate [options]
```
## Bun Runtime
If you're using Bun, run Prisma with `bunx --bun` so it doesn't fall back to Node.js:
```bash
bunx --bun prisma generate
```
## What It Does
1. Reads your `schema.prisma` file
2. Generates a customized Prisma Client based on your models
3. Outputs to the directory specified in the generator block
## Options
| Option | Description |
|--------|-------------|
| `--schema` | Custom path to your Prisma schema |
| `--config` | Custom path to your Prisma config file |
| `--sql` | Generate typed sql module |
| `--watch` | Watch the Prisma schema and rerun after a change |
| `--generator` | Generator to use (may be provided multiple times) |
| `--no-hints` | Hides the hint messages but still outputs errors and warnings |
| `--require-models` | Do not allow generating a client without models |
## Examples
### Basic generation
```bash
prisma generate
```
### Watch mode (development)
```bash
prisma generate --watch
```
Auto-regenerates when `schema.prisma` changes.
### Specific generator
```bash
prisma generate --generator client
```
### Multiple generators
```bash
prisma generate --generator client --generator zod_schemas
```
### Typed SQL generation
```bash
prisma generate --sql
```
## Schema Configuration
```prisma
generator client {
provider = "prisma-client"
output = "../generated"
}
```
### Current Generator Behavior
- `prisma-client` is the standard generator
- `output` is required when using `prisma-client`
- `prisma-client` supports both ESM and CommonJS via `moduleFormat`
- `compilerBuild` supports `fast` and `small` query compiler artifacts
- Use TypeScript `satisfies` for typed query fragments with `prisma-client`
- Import Prisma Client from your generated output path, for example:
```typescript
import { PrismaClient } from '../generated/prisma/client'
```
### Compiler Build Tuning
Use `compilerBuild` when you need to trade artifact size against the default build:
```prisma
generator client {
provider = "prisma-client"
output = "../generated"
compilerBuild = "small"
}
```
- `fast` is the default build for most targets
- `small` is useful for size-constrained targets
- Prisma defaults `vercel-edge` targets to `small`
## Common Patterns
### After schema changes
```bash
prisma migrate dev --name my_migration
prisma generate
```
Run `prisma generate` whenever you need refreshed client code after schema-changing commands.
### CI/CD pipeline
```bash
prisma generate
```
Run before building your application.
### Multiple generators
```prisma
generator client {
provider = "prisma-client"
output = "../generated"
}
generator zod {
provider = "zod-prisma-types"
output = "../generated/zod"
}
```
```bash
prisma generate # Runs all generators
```
## Output Structure
After running `prisma generate`, your output directory contains:
```
generated/
├── browser.ts
├── client.ts
├── commonInputTypes.ts
├── models/
├── enums.ts
├── models.ts
└── ...
```
Import the client:
```typescript
import { PrismaClient, Prisma } from '../generated/prisma/client'
```
Import browser-safe types:
```typescript
import { Prisma } from '../generated/prisma/browser'
import { Role } from '../generated/prisma/enums'
import type { UserModel } from '../generated/prisma/models/User'
```
@@ -0,0 +1,139 @@
# prisma init
Bootstraps a fresh Prisma ORM project in the current directory.
## Command
```bash
prisma init [options]
```
## Bun Runtime
If you're using Bun, run Prisma with `bunx --bun` so it doesn't fall back to Node.js:
```bash
bunx --bun prisma init
```
## What It Creates
- `prisma/schema.prisma` - Your Prisma schema file
- `prisma.config.ts` - TypeScript configuration for Prisma CLI
- `.env` - Environment variables (DATABASE_URL)
- `.gitignore` - Ensures `.env` is ignored and appends the generated client path
## Options
| Option | Description | Default |
|--------|-------------|---------|
| `--datasource-provider` | Database provider: `postgresql`, `mysql`, `sqlite`, `sqlserver`, `mongodb`, `cockroachdb` | `postgresql` |
| `--db` | Provisions a fully managed Prisma Postgres database on the Prisma Data Platform | - |
| `--url` | Define a custom datasource url | - |
| `--generator-provider` | Define the generator provider to use | `prisma-client` |
| `--output` | Define Prisma Client generator output path to use | - |
| `--preview-feature` | Define a preview feature to use | - |
| `--with-model` | Add example model to created schema file | - |
| `--no-skills` | Skip the best-effort installation of Prisma agent skills | - |
`prisma init` attempts to install `prisma/skills` for detected agents. This is best-effort and does not make project initialization fail. Use `--no-skills` in minimal or controlled environments.
## Examples
### Basic initialization
```bash
prisma init
```
Creates a PostgreSQL project setup.
### SQLite project
```bash
prisma init --datasource-provider sqlite
```
### MySQL with custom URL
```bash
prisma init --datasource-provider mysql --url "mysql://user:password@localhost:3306/mydb"
```
### Prisma Postgres (cloud)
```bash
prisma init --db
```
Opens browser for authentication, creates cloud database instance.
### Add an example model
```bash
prisma init --with-model
```
Adds a starter model to the generated schema.
### With preview features
```bash
prisma init --preview-feature relationJoins --preview-feature fullTextSearch
```
## Generated Schema
```prisma
generator client {
provider = "prisma-client"
output = "../generated/prisma"
}
datasource db {
provider = "postgresql"
}
```
## Generated Config (Node.js default)
```typescript
// prisma.config.ts
import "dotenv/config";
import { defineConfig } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
datasource: {
url: process.env['DATABASE_URL'],
},
})
```
## Generated Config (Bun)
```typescript
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
datasource: {
url: env('DATABASE_URL'),
},
})
```
## Next Steps After Init
1. Configure `DATABASE_URL` in `.env` (and let `prisma.config.ts` read it)
2. Define your models in `prisma/schema.prisma`
3. Run `prisma dev` for local development or connect to remote DB
4. Run `prisma migrate dev` to create migrations
5. Run `prisma generate` to generate Prisma Client
6. Run `prisma db seed` explicitly if you want seed data
@@ -0,0 +1,39 @@
# prisma mcp
Starts Prisma's MCP server for AI development tools.
## Command
```bash
prisma mcp
```
## What It Does
- Starts a Model Context Protocol (MCP) server for your Prisma project
- Exposes Prisma schema and database context to compatible AI tools
- Helps AI assistants understand models, generate queries, and suggest migrations
## Usage
```bash
prisma mcp
```
## Typical Use Cases
- Connect Prisma to ChatGPT, Claude, or other MCP-aware tools
- Give an AI assistant access to your Prisma schema structure
- Help an agent propose queries, schema updates, and migration steps with project context
## Notes
- Run this from the project that contains your Prisma schema and `prisma.config.ts`
- The command is separate from Prisma Studio and does not open a browser UI
- The MCP server exposes `migrate-status`, `migrate-dev`, and Prisma Studio tooling. It does not expose the destructive `migrate-reset` tool; do not claim it is available or try to bypass that safety boundary.
- For destructive shell commands, follow `agent-safety.md` and obtain explicit user consent.
## References
- [Prisma CLI `mcp` command](https://docs.prisma.io/docs/cli/mcp)
- [Prisma MCP Server](https://www.prisma.io/docs/ai/tools/chatgpt)
@@ -0,0 +1,127 @@
# prisma migrate deploy
Applies pending migrations in production/staging environments.
## Command
```bash
prisma migrate deploy
```
## What It Does
- Applies all pending migrations from `prisma/migrations/`
- Updates `_prisma_migrations` table
- Does NOT generate new migrations
- Does NOT run seed scripts
- Safe for CI/CD and production
## Options
| Option | Description |
|--------|-------------|
| `--schema` | Custom path to your Prisma schema |
| `--config` | Custom path to your Prisma config file |
## When to Use
- Production deployments
- Staging environments
- CI/CD pipelines
- Any non-development environment
## Examples
### Basic deployment
```bash
prisma migrate deploy
```
### In CI/CD pipeline
```yaml
# GitHub Actions example
- name: Apply migrations
run: npx prisma migrate deploy
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
```
### Docker deployment
```dockerfile
# Run migrations before starting app
CMD npx prisma migrate deploy && node dist/index.js
```
## Comparison with migrate dev
| Feature | migrate dev | migrate deploy |
|---------|-------------|----------------|
| Creates migrations | Yes | No |
| Applies migrations | Yes | Yes |
| Detects drift | Yes | No |
| Prompts for input | Yes | No |
| Uses shadow database | Yes | No |
| Safe for production | No | Yes |
| Resets on issues | Prompts | Fails |
## Production Workflow
1. **Development**: Create migrations locally
```bash
prisma migrate dev --name add_feature
```
2. **Commit**: Include migration files in version control
```bash
git add prisma/migrations
git commit -m "Add feature migration"
```
3. **Deploy**: Apply in production
```bash
prisma migrate deploy
```
## Error Handling
### Failed migration
If a migration fails, `migrate deploy` exits with error. The failed migration is marked as failed in `_prisma_migrations`.
To fix:
1. Resolve the issue (fix SQL, database state, etc.)
2. Mark as resolved: `prisma migrate resolve --applied <migration_name>`
3. Re-run: `prisma migrate deploy`
### Check status first
```bash
prisma migrate status
```
Shows pending and applied migrations before deploying.
## Configuration
Ensure `prisma.config.ts` has the production database URL:
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
datasource: {
url: env('DATABASE_URL'),
},
})
```
## Best Practices
1. Always run `migrate status` before `migrate deploy` in CI
2. Have a rollback plan (backup before migrations)
3. Test migrations in staging first
4. Never use `migrate dev` in production
@@ -0,0 +1,145 @@
# prisma migrate dev
Creates and applies migrations during development. Requires a shadow database.
## Command
```bash
prisma migrate dev [options]
```
## What It Does
1. Runs existing migrations in shadow database to detect drift
2. Applies any pending migrations
3. Generates new migration from schema changes
4. Applies new migration to development database
5. Updates `_prisma_migrations` table
## Options
| Option | Description |
|--------|-------------|
| `--name` / `-n` | Name the migration |
| `--create-only` | Create a new migration but do not apply it |
| `--schema` | Custom path to your Prisma schema |
| `--config` | Custom path to your Prisma config file |
| `--url` | Override the datasource URL from the Prisma config file |
### Follow-up Commands
- Run `prisma generate` explicitly when you need refreshed client output
- Run `prisma db seed` explicitly when you need seed data
Run `prisma generate` as an explicit follow-up when you need refreshed generated artifacts. Do not rely on historical CLI help that described generators as part of `migrate dev`.
## Examples
### Create and apply migration
```bash
prisma migrate dev
```
Prompts for migration name if schema changed.
### Named migration
```bash
prisma migrate dev --name add_users_table
```
### Create without applying
```bash
prisma migrate dev --create-only
```
Useful for reviewing migration SQL before applying.
### Full workflow
```bash
prisma migrate dev --name my_migration
prisma generate
prisma db seed
```
## Migration Files
Created in `prisma/migrations/`:
```
prisma/migrations/
├── 20240115120000_add_users_table/
│ └── migration.sql
├── 20240116090000_add_posts/
│ └── migration.sql
└── migration_lock.toml
```
## Schema Drift Detection
If `migrate dev` detects drift (manual database changes or edited migrations), it prompts to reset:
```
Drift detected: Your database schema is not in sync.
Do you want to reset your database? All data will be lost.
```
## When to Use
- Local development
- Adding new models/fields
- Changing relations
- Creating indexes
## When NOT to Use
- Production deployments (use `migrate deploy`)
- CI/CD pipelines (use `migrate deploy`)
- MongoDB (use `db push` instead)
## Common Patterns
### After schema changes
```prisma
// schema.prisma - Add new field
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
createdAt DateTime @default(now()) // New field
}
```
```bash
prisma migrate dev --name add_created_at
```
### Handling data loss warnings
When a migration would cause data loss:
```bash
prisma migrate dev --name remove_field
# Warning: You are about to delete data...
# Accept with: --accept-data-loss
```
## Shadow Database
`migrate dev` requires a shadow database for drift detection. Configure in `prisma.config.ts`:
```typescript
export default defineConfig({
datasource: {
url: env('DATABASE_URL'),
shadowDatabaseUrl: env('SHADOW_DATABASE_URL'),
},
})
```
For local Prisma Postgres (`prisma dev`), shadow database is handled automatically.
@@ -0,0 +1,89 @@
# prisma migrate diff
Compares database schemas and generates diffs (SQL or summary).
## Command
```bash
prisma migrate diff [options]
```
## What It Does
- Compares two sources (`--from-...` and `--to-...`)
- Sources can be:
- Empty (`empty`)
- Schema file (`schema`)
- Migrations directory (`migrations`)
- Database URL (`url`) or Configured Datasource (`config-datasource`)
- Outputs the difference:
- Human-readable summary (default)
- SQL script (`--script`)
## Options
| Option | Description |
|--------|-------------|
| `--script` | Render SQL script to stdout |
| `--exit-code` | Exit 2 if changes detected, 0 if empty, 1 if error |
| `--config` | Custom path to your Prisma config file |
### Sources (Must provide one `from` and one `to`)
- `--from-empty`, `--to-empty`
- `--from-schema <path>`, `--to-schema <path>`
- `--from-migrations <path>`, `--to-migrations <path>`
- `--from-url <url>`, `--to-url <url>`
- `--from-config-datasource`, `--to-config-datasource` (uses `prisma.config.ts`)
## Examples
### Generate SQL for a schema change
Compare current production DB to your local schema:
```bash
prisma migrate diff \
--from-url "$PROD_DB_URL" \
--to-schema ./prisma/schema.prisma \
--script
```
### Review pending migrations
Compare database state to migrations directory:
```bash
prisma migrate diff \
--from-config-datasource \
--to-migrations ./prisma/migrations
```
### Create baseline migration
Compare empty state to current schema:
```bash
prisma migrate diff \
--from-empty \
--to-schema ./prisma/schema.prisma \
--script > prisma/migrations/0_init/migration.sql
```
### Check for drift (CI)
Check if database matches schema:
```bash
prisma migrate diff \
--from-config-datasource \
--to-schema ./prisma/schema.prisma \
--exit-code
```
## Use Cases
- **Forward-generating migrations**: Creating SQL without `migrate dev`.
- **Drift detection**: Checking if DB is in sync.
- **Baselining**: Creating initial migration from existing DB.
- **Debugging**: Understanding what `migrate dev` would do.
@@ -0,0 +1,80 @@
# prisma migrate reset
Resets your database and re-applies all migrations.
## Command
```bash
prisma migrate reset [options]
```
## What It Does
1. **Drops** the database (if possible) or deletes all data/tables
2. **Re-creates** the database
3. **Applies** all migrations from `prisma/migrations/`
4. Stops there - run seed and generate explicitly if needed
**Warning: All data will be lost.**
When Prisma detects an AI agent, this command is blocked until the user gives explicit consent. Follow `agent-safety.md`; `--force` skips the ordinary prompt but does not constitute user consent for an agent.
## Options
| Option | Description |
|--------|-------------|
| `--force` / `-f` | Skip confirmation prompt |
| `--schema` | Path to schema file |
| `--config` | Custom path to your Prisma config file |
## Examples
### Basic reset
```bash
prisma migrate reset
```
Prompts for confirmation in interactive terminals.
### Force reset (CI/Automation)
```bash
prisma migrate reset --force
```
### With custom schema
```bash
prisma migrate reset --schema=./custom/schema.prisma
```
## When to Use
- **Development**: When you want a fresh start
- **Testing**: Resetting test database before suites
- **Drift Recovery**: When the database is out of sync and you can't migrate
## Follow-up Steps
Run `prisma generate` and `prisma db seed` explicitly when you need refreshed client output or seed data after a reset.
## Configuration
Configure the seed script in `prisma.config.ts`, then run it explicitly after reset:
```typescript
export default defineConfig({
migrations: {
seed: 'tsx prisma/seed.ts',
},
})
```
Typical workflow:
```bash
prisma migrate reset --force
prisma generate
prisma db seed
```
@@ -0,0 +1,57 @@
# prisma migrate resolve
Resolves issues with database migrations, such as failed migrations or baselining.
## Command
```bash
prisma migrate resolve [options]
```
## What It Does
Updates the `_prisma_migrations` table to manually change the state of a migration. This is a recovery tool.
## Options
You must provide exactly one of `--applied` or `--rolled-back`.
| Option | Description |
|--------|-------------|
| `--applied <name>` | Mark a migration as **applied** (success) |
| `--rolled-back <name>` | Mark a migration as **rolled back** (ignored/failed) |
| `--schema` | Path to schema file |
| `--config` | Custom path to your Prisma config file |
## Examples
### Mark as Applied (Baselining)
If you have existing tables and want to initialize migrations without running the SQL:
```bash
prisma migrate resolve --applied 20240101000000_initial_migration
```
This tells Prisma "Assume this migration has already run".
### Mark as Rolled Back (Fixing Failures)
If a migration failed (e.g., syntax error) and you fixed the SQL or want to retry:
```bash
prisma migrate resolve --rolled-back 20240115120000_failed_migration
```
This tells Prisma "Forget this migration run, let me try applying it again".
## Use Cases
1. **Baselining**: Adopting Prisma Migrate on an existing production database.
2. **Failed Migrations**: Recovering from a failed `migrate deploy` in production.
3. **Hotfixes**: reconciling manual database changes (rare).
## References
- [Baselining](https://www.prisma.io/docs/guides/database/developing-with-prisma-migrate/baselining)
- [Troubleshooting](https://www.prisma.io/docs/guides/database/production-troubleshooting)
@@ -0,0 +1,65 @@
# prisma migrate status
Checks the status of your database migrations.
## Command
```bash
prisma migrate status [options]
```
## What It Does
- Connects to the database
- Checks the `_prisma_migrations` table
- Compares applied migrations with local migration files
- Reports:
- **Status**: Database is up-to-date or behind
- **Unapplied migrations**: Count of pending migrations
- **Missing migrations**: Migrations present in DB but missing locally
- **Failed migrations**: Any migrations that failed to apply
## Options
| Option | Description |
|--------|-------------|
| `--schema` | Path to schema file |
| `--config` | Custom path to your Prisma config file |
## Examples
### Check status
```bash
prisma migrate status
```
Output example (Up to date):
```
Database schema is up to date!
```
Output example (Pending):
```
Following migration have not yet been applied:
20240115120000_add_user
To apply migrations in development, run:
prisma migrate dev
To apply migrations in production, run:
prisma migrate deploy
```
## When to Use
- **Debugging**: Why is `migrate dev` complaining about drift?
- **CI/CD**: Verify database state before deploying
- **Production**: Check if migrations are needed (`migrate deploy`) or if a deployment failed
## Exit Codes
- `0`: Success (may have pending migrations, but command ran successfully)
- `1`: Error
To check for pending migrations programmatically, you might need to parse the output or use `migrate diff` with exit code flags.
@@ -0,0 +1,137 @@
# prisma studio
Opens a visual database browser for viewing and editing data.
## Command
```bash
prisma studio [options]
```
## What It Does
- Starts a web-based database GUI
- View all your models and records
- Create, update, and delete records
- Filter and sort data
- Navigate relations
## Options
| Option | Description | Default |
|--------|-------------|---------|
| `--port` / `-p` | Port to start Studio on | `5555` |
| `--browser` / `-b` | Browser to open Studio in | System default |
| `--config` | Custom path to your Prisma config file | - |
| `--url` | Database connection string (overrides the one in your Prisma config) | - |
## Examples
### Open Studio
```bash
prisma studio
```
Opens at http://localhost:5555
### Custom port
```bash
prisma studio --port 3000
```
### Specific browser
```bash
prisma studio --browser firefox
```
### Don't open browser
```bash
BROWSER=none prisma studio
```
Useful for remote servers.
## Features
### View Records
- See all records in table format
- Pagination for large datasets
- Column sorting
### Filter Data
- Filter by any field
- Multiple conditions
- Relation filtering
### Edit Records
- Click to edit inline
- Add new records
- Delete records (with confirmation)
### Navigate Relations
- Click relations to view related records
- See counts of related items
- Follow relation links
## Recent Studio Capabilities
Recent Prisma Studio releases added richer editor workflows:
- multi-cell selection and editing
- full-table search and more intuitive filtering
- command palette shortcuts
- dark mode
- copy selections as Markdown
- back-relation navigation
- SQL workflows including raw SQL queries
Some recent builds also expose AI-assisted SQL authoring. Treat these as interactive Studio features rather than a replacement for checked-in migrations or application queries.
## Use Cases
- **Development**: Quick data inspection
- **Debugging**: Check data state
- **Testing**: Verify seed data
- **Demo**: Show data to stakeholders
## Limitations
- Development tool only
- Not for production use
- Limited to configured database
- Prisma Studio in Prisma 7 currently targets PostgreSQL, MySQL, and SQLite first
- For reproducible application logic, prefer Prisma Client and checked-in SQL scripts
## Common Workflow
1. Run migrations:
```bash
prisma migrate dev
```
2. Seed data:
```bash
prisma db seed
```
3. Open Studio to verify:
```bash
prisma studio
```
4. Make manual edits if needed
## Security Note
Studio provides direct database access. Only run on:
- Local development machines
- Secure internal networks
- Never expose publicly
@@ -0,0 +1,53 @@
# prisma validate
Validates your Prisma schema file.
## Command
```bash
prisma validate [options]
```
## What It Does
- Parses the `schema.prisma` file
- Checks for syntax errors
- Validates model definitions, relations, and types
- Reports any errors or warnings without generating code
## Options
| Option | Description |
|--------|-------------|
| `--schema` | Path to schema file |
| `--config` | Custom path to your Prisma config file |
## Examples
### Validate default schema
```bash
prisma validate
```
### Validate specific schema
```bash
prisma validate --schema=./custom/schema.prisma
```
### Use in CI
Run `validate` in your CI pipeline to catch schema errors early:
```yaml
- name: Validate Schema
run: npx prisma validate
```
## Common Errors
- Missing `@relation` fields
- Invalid types
- Duplicate model names
- Syntax errors (missing braces, etc.)
@@ -0,0 +1,216 @@
---
name: prisma-client-api
description: Prisma Client API reference covering model queries, filters, operators, and client methods. Use when writing database queries, using CRUD operations, filtering data, or configuring Prisma Client. Triggers on "prisma query", "findMany", "create", "update", "delete", "$transaction".
license: MIT
metadata:
author: prisma
version: "7.9.1"
---
# Prisma Client API Reference
Complete API reference for Prisma Client. This skill provides guidance on model queries, filtering, relations, and client methods for current Prisma projects.
## When to Apply
Reference this skill when:
- Writing database queries with Prisma Client
- Performing CRUD operations (create, read, update, delete)
- Filtering and sorting data
- Working with relations
- Using transactions
- Configuring client options
## Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | Client Construction | HIGH | `constructor` |
| 2 | Model Queries | CRITICAL | `model-queries` |
| 3 | Query Shape | HIGH | `query-options` |
| 4 | Filtering | HIGH | `filters` |
| 5 | Relations | HIGH | `relations` |
| 6 | Transactions | CRITICAL | `transactions` |
| 7 | Raw SQL | CRITICAL | `raw-queries` |
| 8 | Client Methods | MEDIUM | `client-methods` |
## Quick Reference
- `constructor` - `PrismaClient` setup, adapter wiring, logging, and SQL commenter plugins
- `model-queries` - CRUD operations and bulk operations
- `query-options` - `select`, `include`, `omit`, sort, pagination
- `filters` - scalar and logical filter operators
- `relations` - relation reads and nested writes
- `transactions` - array and interactive transaction patterns
- `raw-queries` - `$queryRaw` and `$executeRaw` safety
- `client-methods` - lifecycle methods, extensions, and `satisfies` patterns for `prisma-client`
## Client Instantiation
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL
})
const prisma = new PrismaClient({ adapter })
```
## Model Query Methods
| Method | Description |
|--------|-------------|
| `findUnique()` | Find one record by unique field |
| `findUniqueOrThrow()` | Find one or throw error |
| `findFirst()` | Find first matching record |
| `findFirstOrThrow()` | Find first or throw error |
| `findMany()` | Find multiple records |
| `create()` | Create a new record |
| `createMany()` | Create multiple records |
| `createManyAndReturn()` | Create multiple and return them |
| `update()` | Update one record |
| `updateMany()` | Update multiple records |
| `updateManyAndReturn()` | Update multiple and return them |
| `upsert()` | Update or create record |
| `delete()` | Delete one record |
| `deleteMany()` | Delete multiple records |
| `count()` | Count matching records |
| `aggregate()` | Aggregate values (sum, avg, etc.) |
| `groupBy()` | Group and aggregate |
## Query Options
| Option | Description |
|--------|-------------|
| `where` | Filter conditions |
| `select` | Fields to include |
| `include` | Relations to load |
| `omit` | Fields to exclude |
| `orderBy` | Sort order |
| `take` | Limit results |
| `skip` | Skip results (pagination) |
| `cursor` | Cursor-based pagination |
| `distinct` | Unique values only |
## Client Methods
| Method | Description |
|--------|-------------|
| `$connect()` | Explicitly connect to database |
| `$disconnect()` | Disconnect from database |
| `$transaction()` | Execute transaction |
| `$queryRaw()` | Execute raw SQL query |
| `$executeRaw()` | Execute raw SQL command |
| `$on()` | Subscribe to events |
| `$extends()` | Add extensions |
## Quick Examples
### Find records
```typescript
// Find by unique field
const user = await prisma.user.findUnique({
where: { email: 'alice@prisma.io' }
})
// Find with filter
const users = await prisma.user.findMany({
where: { role: 'ADMIN' },
orderBy: { createdAt: 'desc' },
take: 10
})
```
### Create records
```typescript
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
name: 'Alice',
posts: {
create: { title: 'Hello World' }
}
},
include: { posts: true }
})
```
### Update records
```typescript
const user = await prisma.user.update({
where: { id: 1 },
data: { name: 'Alice Smith' }
})
```
### Delete records
```typescript
await prisma.user.delete({
where: { id: 1 }
})
```
### Transactions
```typescript
const [user, post] = await prisma.$transaction([
prisma.user.create({ data: { email: 'alice@prisma.io' } }),
prisma.post.create({ data: { title: 'Hello', authorId: 1 } })
])
```
## Rule Files
Detailed API documentation:
```
references/constructor.md - PrismaClient constructor options
references/model-queries.md - CRUD operations
references/query-options.md - select, include, omit, where, orderBy
references/filters.md - Filter conditions and operators
references/relations.md - Relation queries and nested operations
references/transactions.md - Transaction API
references/raw-queries.md - $queryRaw, $executeRaw
references/client-methods.md - $connect, $disconnect, $on, $extends
```
## Filter Operators
| Operator | Description |
|----------|-------------|
| `equals` | Exact match |
| `not` | Not equal |
| `in` | In array |
| `notIn` | Not in array |
| `lt`, `lte` | Less than |
| `gt`, `gte` | Greater than |
| `contains` | String contains |
| `startsWith` | String starts with |
| `endsWith` | String ends with |
| `mode` | Case sensitivity |
## Relation Filters
| Operator | Description |
|----------|-------------|
| `some` | At least one related record matches |
| `every` | All related records match |
| `none` | No related records match |
| `is` | Related record matches (1-to-1) |
| `isNot` | Related record doesn't match |
## Resources
- [Prisma Client API Reference](https://www.prisma.io/docs/orm/reference/prisma-client-reference)
- [CRUD Operations](https://www.prisma.io/docs/orm/prisma-client/queries/crud)
- [Filtering and Sorting](https://www.prisma.io/docs/orm/prisma-client/queries/filtering-and-sorting)
## How to Use
Pick the category from the table above, then open the matching reference file for implementation details and examples.
@@ -0,0 +1,223 @@
# Client Methods
Prisma Client instance methods.
## $connect()
Explicitly connect to the database:
```typescript
const prisma = new PrismaClient({ adapter })
// Explicit connection
await prisma.$connect()
```
### When to use
Usually not needed - Prisma connects automatically on first query. Use for:
- Fail fast on startup
- Health checks
- Pre-warming connections
```typescript
async function main() {
try {
await prisma.$connect()
console.log('Database connected')
} catch (e) {
console.error('Failed to connect:', e)
process.exit(1)
}
}
```
## $disconnect()
Close database connection:
```typescript
await prisma.$disconnect()
```
### Graceful shutdown
```typescript
process.on('beforeExit', async () => {
await prisma.$disconnect()
})
// Or with SIGTERM
process.on('SIGTERM', async () => {
await prisma.$disconnect()
process.exit(0)
})
```
### In tests
```typescript
afterAll(async () => {
await prisma.$disconnect()
})
```
## $on()
Subscribe to events:
### Query events
```typescript
const prisma = new PrismaClient({
adapter,
log: [{ level: 'query', emit: 'event' }]
})
prisma.$on('query', (e) => {
console.log('Query:', e.query)
console.log('Params:', e.params)
console.log('Duration:', e.duration, 'ms')
})
```
### Log events
```typescript
const prisma = new PrismaClient({
adapter,
log: [
{ level: 'info', emit: 'event' },
{ level: 'warn', emit: 'event' },
{ level: 'error', emit: 'event' }
]
})
prisma.$on('info', (e) => console.log(e.message))
prisma.$on('warn', (e) => console.warn(e.message))
prisma.$on('error', (e) => console.error(e.message))
```
## $extends()
Add extensions for custom behavior:
### Add custom methods
```typescript
const prisma = new PrismaClient({ adapter }).$extends({
client: {
$log: (message: string) => console.log(message)
}
})
prisma.$log('Hello!')
```
### Add model methods
```typescript
const prisma = new PrismaClient({ adapter }).$extends({
model: {
user: {
async findByEmail(email: string) {
return prisma.user.findUnique({ where: { email } })
}
}
}
})
const user = await prisma.user.findByEmail('alice@prisma.io')
```
### Query extensions
```typescript
const prisma = new PrismaClient({ adapter }).$extends({
query: {
user: {
async findMany({ args, query }) {
// Add default filter
args.where = { ...args.where, deletedAt: null }
return query(args)
}
}
}
})
```
### Result extensions
```typescript
const prisma = new PrismaClient({ adapter }).$extends({
result: {
user: {
fullName: {
needs: { firstName: true, lastName: true },
compute(user) {
return `${user.firstName} ${user.lastName}`
}
}
}
}
})
const user = await prisma.user.findFirst()
console.log(user.fullName) // Computed field
```
### Chain extensions
```typescript
const prisma = new PrismaClient({ adapter })
.$extends(loggingExtension)
.$extends(softDeleteExtension)
.$extends(computedFieldsExtension)
```
## $transaction()
See `transactions.md` for details.
## $queryRaw() / $executeRaw()
See `raw-queries.md` for details.
## Type utilities
### Prisma namespace
```typescript
import { Prisma } from '../generated/client'
// Input types
type UserCreateInput = Prisma.UserCreateInput
type UserWhereInput = Prisma.UserWhereInput
// Output types
type User = Prisma.UserGetPayload<{}>
type UserWithPosts = Prisma.UserGetPayload<{
include: { posts: true }
}>
```
### Type-safe query fragments with satisfies
Type-safe query fragments:
```typescript
import { Prisma } from '../generated/client'
const userSelect = {
id: true,
email: true,
name: true
} satisfies Prisma.UserSelect
const user = await prisma.user.findUnique({
where: { id: 1 },
select: userSelect
})
```
With the `prisma-client` generator, use TypeScript `satisfies` for typed query fragments. You may still see older examples that use `Prisma.validator()` with `prisma-client-js`.
@@ -0,0 +1,221 @@
# PrismaClient Constructor
Configure Prisma Client when instantiating.
## Basic Instantiation
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL
})
const prisma = new PrismaClient({ adapter })
```
## Constructor Options
### adapter (Required for the SQL provider workflow)
Driver adapter instance:
```typescript
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL
})
const prisma = new PrismaClient({ adapter })
```
### accelerateUrl (For Accelerate users)
```typescript
import { withAccelerate } from '@prisma/extension-accelerate'
const prisma = new PrismaClient({
accelerateUrl: process.env.DATABASE_URL, // prisma:// URL
}).$extends(withAccelerate())
```
### log
Configure logging:
```typescript
const prisma = new PrismaClient({
adapter,
log: ['query', 'info', 'warn', 'error'],
})
```
#### Log levels
| Level | Description |
|-------|-------------|
| `query` | All SQL queries |
| `info` | Informational messages |
| `warn` | Warnings |
| `error` | Errors |
#### Log to events
```typescript
const prisma = new PrismaClient({
adapter,
log: [
{ level: 'query', emit: 'event' },
{ level: 'error', emit: 'stdout' },
],
})
prisma.$on('query', (e) => {
console.log('Query:', e.query)
console.log('Duration:', e.duration, 'ms')
})
```
### errorFormat
Control error formatting:
```typescript
const prisma = new PrismaClient({
adapter,
errorFormat: 'pretty', // 'pretty' | 'colorless' | 'minimal'
})
```
### comments
Attach SQL commenter plugins for observability, tracing, or query insights:
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
import { prismaQueryInsights } from '@prisma/sqlcommenter-query-insights'
import { queryTags, withQueryTags } from '@prisma/sqlcommenter-query-tags'
import { traceContext } from '@prisma/sqlcommenter-trace-context'
const prisma = new PrismaClient({
adapter: new PrismaPg(process.env.DATABASE_URL!),
comments: [prismaQueryInsights(), traceContext(), queryTags()],
})
await withQueryTags({ route: '/api/users', requestId: 'req-123' }, () =>
prisma.user.findMany(),
)
```
Use `comments` only for SQL providers. This is the clean way to add trace or query-shape metadata without changing your query calls.
### transactionOptions
Default transaction settings:
```typescript
const prisma = new PrismaClient({
adapter,
transactionOptions: {
maxWait: 5000, // Max wait to acquire transaction (ms)
timeout: 10000, // Max transaction duration (ms)
isolationLevel: 'Serializable',
},
})
```
### queryPlanCacheMaxSize
Use `queryPlanCacheMaxSize` to limit the in-memory query-plan cache:
```typescript
const prisma = new PrismaClient({
adapter,
queryPlanCacheMaxSize: 2_000,
})
```
The value must be a non-negative integer. Set it to `0` to disable query-plan caching; omit it to use Prisma's default. Treat this as a process-local memory/performance control, not a database prepared-statement setting.
## Singleton Pattern
Prevent multiple client instances in development:
```typescript
// lib/prisma.ts
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined
}
function createPrismaClient() {
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL!
})
return new PrismaClient({ adapter })
}
export const prisma = globalForPrisma.prisma ?? createPrismaClient()
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma
}
```
## Next.js Pattern
```typescript
// lib/prisma.ts
import { PrismaClient } from '@/generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const createAdapter = () => new PrismaPg({
connectionString: process.env.DATABASE_URL!
})
const prismaClientSingleton = () => {
return new PrismaClient({ adapter: createAdapter() })
}
declare const globalThis: {
prismaGlobal: ReturnType<typeof prismaClientSingleton>
} & typeof global
const prisma = globalThis.prismaGlobal ?? prismaClientSingleton()
export default prisma
if (process.env.NODE_ENV !== 'production') {
globalThis.prismaGlobal = prisma
}
```
## Query Events
Listen to query events:
```typescript
const prisma = new PrismaClient({
adapter,
log: [{ level: 'query', emit: 'event' }],
})
prisma.$on('query', (e) => {
console.log('Query:', e.query)
console.log('Params:', e.params)
console.log('Duration:', e.duration)
})
```
## Log Events
```typescript
prisma.$on('info', (e) => console.log(e.message))
prisma.$on('warn', (e) => console.warn(e.message))
prisma.$on('error', (e) => console.error(e.message))
```
@@ -0,0 +1,256 @@
# Filter Conditions and Operators
Filter operators for the `where` clause.
## Equality
```typescript
// Exact match (implicit)
where: { email: 'alice@prisma.io' }
// Explicit equals
where: { email: { equals: 'alice@prisma.io' } }
// Not equal
where: { email: { not: 'alice@prisma.io' } }
```
## Comparison
```typescript
// Greater than
where: { age: { gt: 18 } }
// Greater than or equal
where: { age: { gte: 18 } }
// Less than
where: { age: { lt: 65 } }
// Less than or equal
where: { age: { lte: 65 } }
// Combined
where: { age: { gte: 18, lte: 65 } }
```
## Lists
```typescript
// In array
where: { role: { in: ['ADMIN', 'MODERATOR'] } }
// Not in array
where: { role: { notIn: ['GUEST', 'BANNED'] } }
```
## String Filters
```typescript
// Contains
where: { email: { contains: 'prisma' } }
// Starts with
where: { email: { startsWith: 'alice' } }
// Ends with
where: { email: { endsWith: '@prisma.io' } }
// Case-insensitive (default for some databases)
where: {
email: {
contains: 'PRISMA',
mode: 'insensitive'
}
}
```
## Null Checks
```typescript
// Is null
where: { deletedAt: null }
// Is not null
where: { deletedAt: { not: null } }
// Using isSet (for optional fields)
where: { middleName: { isSet: true } }
```
## Logical Operators
### AND (implicit)
```typescript
// Multiple conditions = AND
where: {
email: { contains: '@prisma.io' },
role: 'ADMIN'
}
```
### AND (explicit)
```typescript
where: {
AND: [
{ email: { contains: '@prisma.io' } },
{ role: 'ADMIN' }
]
}
```
### OR
```typescript
where: {
OR: [
{ email: { contains: '@gmail.com' } },
{ email: { contains: '@prisma.io' } }
]
}
```
### NOT
```typescript
where: {
NOT: {
role: 'GUEST'
}
}
// Multiple NOT conditions
where: {
NOT: [
{ role: 'GUEST' },
{ verified: false }
]
}
```
### Combined
```typescript
where: {
AND: [
{ verified: true },
{
OR: [
{ role: 'ADMIN' },
{ role: 'MODERATOR' }
]
}
],
NOT: { deletedAt: { not: null } }
}
```
## Relation Filters
### some
At least one related record matches:
```typescript
// Users with at least one published post
where: {
posts: {
some: { published: true }
}
}
```
### every
All related records match:
```typescript
// Users where all posts are published
where: {
posts: {
every: { published: true }
}
}
```
### none
No related records match:
```typescript
// Users with no published posts
where: {
posts: {
none: { published: true }
}
}
```
### is / isNot (1-to-1)
```typescript
// Users with profile in specific country
where: {
profile: {
is: { country: 'USA' }
}
}
// Users without profile
where: {
profile: {
isNot: null
}
}
```
## Array Field Filters
For fields like `String[]`:
```typescript
// Has element
where: { tags: { has: 'typescript' } }
// Has some elements
where: { tags: { hasSome: ['typescript', 'javascript'] } }
// Has every element
where: { tags: { hasEvery: ['typescript', 'prisma'] } }
// Is empty
where: { tags: { isEmpty: true } }
```
## JSON Filters
```typescript
// Path-based filter
where: {
metadata: {
path: ['settings', 'theme'],
equals: 'dark'
}
}
// String contains in JSON
where: {
metadata: {
path: ['bio'],
string_contains: 'developer'
}
}
```
## Full-Text Search
```typescript
// Requires @@fulltext index
where: {
content: {
search: 'prisma database'
}
}
```
@@ -0,0 +1,281 @@
# Model Queries
CRUD operations for your Prisma models.
## Read Operations
### findUnique
Find a single record by unique field:
```typescript
const user = await prisma.user.findUnique({
where: { id: 1 }
})
const user = await prisma.user.findUnique({
where: { email: 'alice@prisma.io' }
})
```
#### With composite unique key
```typescript
// Model with @@unique([firstName, lastName])
const user = await prisma.user.findUnique({
where: {
firstName_lastName: {
firstName: 'Alice',
lastName: 'Smith'
}
}
})
```
### findUniqueOrThrow
Same as findUnique but throws if not found:
```typescript
const user = await prisma.user.findUniqueOrThrow({
where: { id: 1 }
})
// Throws PrismaClientKnownRequestError if not found
```
### findFirst
Find first matching record:
```typescript
const user = await prisma.user.findFirst({
where: { role: 'ADMIN' },
orderBy: { createdAt: 'desc' }
})
```
### findFirstOrThrow
```typescript
const user = await prisma.user.findFirstOrThrow({
where: { role: 'ADMIN' }
})
```
### findMany
Find multiple records:
```typescript
const users = await prisma.user.findMany({
where: { role: 'USER' },
orderBy: { name: 'asc' },
take: 10,
skip: 0
})
```
## Create Operations
### create
Create a single record:
```typescript
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
name: 'Alice'
}
})
```
#### With relations
```typescript
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
posts: {
create: [
{ title: 'First Post' },
{ title: 'Second Post' }
]
}
},
include: { posts: true }
})
```
### createMany
Create multiple records:
```typescript
const result = await prisma.user.createMany({
data: [
{ email: 'alice@prisma.io', name: 'Alice' },
{ email: 'bob@prisma.io', name: 'Bob' }
],
skipDuplicates: true // Skip records with duplicate unique fields
})
// Returns { count: 2 }
```
### createManyAndReturn
Create multiple and return them:
```typescript
const users = await prisma.user.createManyAndReturn({
data: [
{ email: 'alice@prisma.io', name: 'Alice' },
{ email: 'bob@prisma.io', name: 'Bob' }
]
})
// Returns array of created users
```
## Update Operations
### update
Update a single record:
```typescript
const user = await prisma.user.update({
where: { id: 1 },
data: { name: 'Alice Smith' }
})
```
#### Atomic operations
```typescript
const post = await prisma.post.update({
where: { id: 1 },
data: {
views: { increment: 1 },
likes: { decrement: 1 },
score: { multiply: 2 },
rating: { divide: 2 },
version: { set: 5 }
}
})
```
### updateMany
Update multiple records:
```typescript
const result = await prisma.user.updateMany({
where: { role: 'USER' },
data: { verified: true }
})
// Returns { count: 42 }
```
### updateManyAndReturn
```typescript
const users = await prisma.user.updateManyAndReturn({
where: { role: 'USER' },
data: { verified: true }
})
// Returns array of updated users
```
### upsert
Update or create:
```typescript
const user = await prisma.user.upsert({
where: { email: 'alice@prisma.io' },
update: { name: 'Alice Smith' },
create: { email: 'alice@prisma.io', name: 'Alice' }
})
```
## Delete Operations
### delete
Delete a single record:
```typescript
const user = await prisma.user.delete({
where: { id: 1 }
})
// Returns deleted record
```
### deleteMany
Delete multiple records:
```typescript
const result = await prisma.user.deleteMany({
where: { role: 'GUEST' }
})
// Returns { count: 5 }
// Delete all
const result = await prisma.user.deleteMany({})
```
## Aggregation Operations
### count
```typescript
const count = await prisma.user.count({
where: { role: 'ADMIN' }
})
```
### aggregate
```typescript
const result = await prisma.post.aggregate({
_avg: { views: true },
_sum: { views: true },
_min: { views: true },
_max: { views: true },
_count: { _all: true }
})
```
### groupBy
```typescript
const groups = await prisma.user.groupBy({
by: ['country'],
_count: { _all: true },
_avg: { age: true },
having: {
age: { _avg: { gt: 30 } }
}
})
```
## Return Types
| Method | Returns |
|--------|---------|
| `findUnique` | Record \| null |
| `findUniqueOrThrow` | Record (throws if not found) |
| `findFirst` | Record \| null |
| `findFirstOrThrow` | Record (throws if not found) |
| `findMany` | Record[] |
| `create` | Record |
| `createMany` | { count: number } |
| `createManyAndReturn` | Record[] |
| `update` | Record |
| `updateMany` | { count: number } |
| `delete` | Record |
| `deleteMany` | { count: number } |
| `count` | number |
| `aggregate` | Aggregate result |
| `groupBy` | Group result[] |
@@ -0,0 +1,276 @@
# Query Options
Options for controlling query behavior.
## select
Choose specific fields to return:
```typescript
const user = await prisma.user.findUnique({
where: { id: 1 },
select: {
id: true,
name: true,
email: true,
// password: false (excluded by not including)
}
})
// Returns: { id: 1, name: 'Alice', email: 'alice@prisma.io' }
```
### Select relations
```typescript
const user = await prisma.user.findUnique({
where: { id: 1 },
select: {
name: true,
posts: {
select: {
title: true,
published: true
}
}
}
})
```
### Select with include inside
```typescript
const user = await prisma.user.findMany({
select: {
name: true,
posts: {
include: {
comments: true
}
}
}
})
```
### Select relation count
```typescript
const users = await prisma.user.findMany({
select: {
name: true,
_count: {
select: { posts: true }
}
}
})
// Returns: { name: 'Alice', _count: { posts: 5 } }
```
## include
Include related records:
```typescript
const user = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: true,
profile: true
}
})
```
### Filtered include
```typescript
const user = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: {
where: { published: true },
orderBy: { createdAt: 'desc' },
take: 5
}
}
})
```
### Nested include
```typescript
const user = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: {
include: {
comments: {
include: {
author: true
}
}
}
}
}
})
```
### Include relation count
```typescript
const users = await prisma.user.findMany({
include: {
_count: {
select: { posts: true, followers: true }
}
}
})
```
## omit
Exclude specific fields:
```typescript
const user = await prisma.user.findUnique({
where: { id: 1 },
omit: {
password: true
}
})
// Returns all fields except password
```
### Omit in relations
```typescript
const users = await prisma.user.findMany({
omit: { password: true },
include: {
posts: {
omit: { content: true }
}
}
})
```
**Note:** Cannot use `select` and `omit` together.
## where
Filter records:
```typescript
const users = await prisma.user.findMany({
where: {
email: { contains: '@prisma.io' },
role: 'ADMIN'
}
})
```
See `filters.md` for detailed filter operators.
## orderBy
Sort results:
```typescript
// Single field
const users = await prisma.user.findMany({
orderBy: { name: 'asc' }
})
// Multiple fields
const users = await prisma.user.findMany({
orderBy: [
{ role: 'desc' },
{ name: 'asc' }
]
})
```
### Order by relation
```typescript
const users = await prisma.user.findMany({
orderBy: {
posts: { _count: 'desc' }
}
})
```
### Null handling
```typescript
const users = await prisma.user.findMany({
orderBy: {
name: { sort: 'asc', nulls: 'last' }
}
})
```
## take & skip
Pagination:
```typescript
// First page
const users = await prisma.user.findMany({
take: 10,
skip: 0
})
// Second page
const users = await prisma.user.findMany({
take: 10,
skip: 10
})
```
### Negative take (reverse)
```typescript
const lastUsers = await prisma.user.findMany({
take: -10,
orderBy: { id: 'asc' }
})
// Returns last 10 users
```
## cursor
Cursor-based pagination:
```typescript
// First page
const firstPage = await prisma.user.findMany({
take: 10,
orderBy: { id: 'asc' }
})
// Next page using cursor
const nextPage = await prisma.user.findMany({
take: 10,
skip: 1, // Skip the cursor record
cursor: { id: firstPage[firstPage.length - 1].id },
orderBy: { id: 'asc' }
})
```
## distinct
Return unique values:
```typescript
const cities = await prisma.user.findMany({
distinct: ['city'],
select: { city: true }
})
```
### Multiple distinct fields
```typescript
const locations = await prisma.user.findMany({
distinct: ['city', 'country']
})
```
@@ -0,0 +1,198 @@
# Raw Queries
Execute raw SQL when Prisma's query API isn't sufficient.
## $queryRaw
Execute SELECT queries and get typed results:
```typescript
const users = await prisma.$queryRaw`
SELECT * FROM "User" WHERE email LIKE ${'%@prisma.io'}
`
```
### With type
```typescript
type User = { id: number; email: string; name: string | null }
const users = await prisma.$queryRaw<User[]>`
SELECT id, email, name FROM "User" WHERE role = ${'ADMIN'}
`
```
### Dynamic table/column names
Use `Prisma.raw()` for identifiers (not safe for user input):
```typescript
import { Prisma } from '../generated/client'
const column = 'email'
const users = await prisma.$queryRaw`
SELECT ${Prisma.raw(column)} FROM "User"
`
```
### With Prisma.sql
Build queries dynamically:
```typescript
import { Prisma } from '../generated/client'
const email = 'alice@prisma.io'
const query = Prisma.sql`SELECT * FROM "User" WHERE email = ${email}`
const users = await prisma.$queryRaw(query)
```
### Join multiple SQL fragments
```typescript
import { Prisma } from '../generated/client'
const conditions = [
Prisma.sql`role = ${'ADMIN'}`,
Prisma.sql`verified = ${true}`
]
const users = await prisma.$queryRaw`
SELECT * FROM "User"
WHERE ${Prisma.join(conditions, ' AND ')}
`
```
## $executeRaw
Execute INSERT, UPDATE, DELETE (returns affected count):
```typescript
const count = await prisma.$executeRaw`
UPDATE "User" SET verified = true WHERE email LIKE ${'%@prisma.io'}
`
console.log(`Updated ${count} users`)
```
### Delete example
```typescript
const deleted = await prisma.$executeRaw`
DELETE FROM "User" WHERE "deletedAt" < ${thirtyDaysAgo}
`
```
### Insert example
```typescript
const inserted = await prisma.$executeRaw`
INSERT INTO "Log" (message, level, timestamp)
VALUES (${message}, ${level}, ${new Date()})
`
```
## $queryRawUnsafe / $executeRawUnsafe
For fully dynamic queries (use with caution!):
```typescript
// ⚠️ SQL injection risk - only use with trusted input
const table = 'User'
const users = await prisma.$queryRawUnsafe(
`SELECT * FROM "${table}" WHERE id = $1`,
userId
)
```
### Parameterized unsafe query
```typescript
const result = await prisma.$executeRawUnsafe(
'UPDATE "User" SET name = $1 WHERE id = $2',
'Alice',
1
)
```
## SQL Injection Prevention
### Safe (parameterized)
```typescript
// ✅ User input is parameterized
const email = userInput
const users = await prisma.$queryRaw`
SELECT * FROM "User" WHERE email = ${email}
`
```
### Unsafe (concatenation)
```typescript
// ❌ SQL injection vulnerability!
const email = userInput
const users = await prisma.$queryRawUnsafe(
`SELECT * FROM "User" WHERE email = '${email}'`
)
```
## Database-Specific Features
### PostgreSQL
```typescript
// Array operations
const users = await prisma.$queryRaw`
SELECT * FROM "User" WHERE 'admin' = ANY(roles)
`
// JSON operations
const users = await prisma.$queryRaw`
SELECT * FROM "User" WHERE metadata->>'theme' = 'dark'
`
```
### MySQL
```typescript
// Full-text search
const posts = await prisma.$queryRaw`
SELECT * FROM Post WHERE MATCH(title, content) AGAINST(${searchTerm})
`
```
## Transactions with Raw Queries
```typescript
await prisma.$transaction(async (tx) => {
await tx.$executeRaw`UPDATE "Account" SET balance = balance - ${amount} WHERE id = ${senderId}`
await tx.$executeRaw`UPDATE "Account" SET balance = balance + ${amount} WHERE id = ${recipientId}`
})
```
## Handling Results
### BigInt handling
PostgreSQL returns BigInt for COUNT:
```typescript
const result = await prisma.$queryRaw<[{ count: bigint }]>`
SELECT COUNT(*) as count FROM "User"
`
const count = Number(result[0].count)
```
### Date handling
```typescript
type Result = { createdAt: Date }
const users = await prisma.$queryRaw<Result[]>`
SELECT "createdAt" FROM "User"
`
// createdAt is already a Date object
```
Invalid JavaScript `Date` values passed to raw queries fail validation instead of being silently serialized as `null`. Validate date input at the application boundary; do not rely on `new Date(badValue)` reaching the database.
When a driver adapter returns an unmapped database-specific error, Prisma surfaces `P2039` with the adapter's preserved original code/message. If those details are missing, fix the adapter mapping rather than parsing rendered error text.
@@ -0,0 +1,308 @@
# Relation Queries
Query and modify related records.
## Include Relations
Load related records:
```typescript
const user = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: true,
profile: true
}
})
```
### Filtered include
```typescript
const user = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: {
where: { published: true },
orderBy: { createdAt: 'desc' },
take: 5,
select: { id: true, title: true }
}
}
})
```
### Nested include
```typescript
const user = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: {
include: {
comments: {
include: { author: true }
}
}
}
}
})
```
## Select Relations
```typescript
const user = await prisma.user.findUnique({
where: { id: 1 },
select: {
name: true,
posts: {
select: { title: true }
}
}
})
```
## Nested Writes
### Create with relations
```typescript
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
posts: {
create: [
{ title: 'Post 1' },
{ title: 'Post 2' }
]
},
profile: {
create: { bio: 'Hello!' }
}
}
})
```
### Create or connect
```typescript
const post = await prisma.post.create({
data: {
title: 'New Post',
author: {
connectOrCreate: {
where: { email: 'alice@prisma.io' },
create: { email: 'alice@prisma.io', name: 'Alice' }
}
}
}
})
```
### Connect existing
```typescript
const post = await prisma.post.create({
data: {
title: 'New Post',
author: {
connect: { id: 1 }
}
}
})
// Shorthand for foreign key
const post = await prisma.post.create({
data: {
title: 'New Post',
authorId: 1
}
})
```
## Update Relations
### Update related records
```typescript
const user = await prisma.user.update({
where: { id: 1 },
data: {
posts: {
update: {
where: { id: 1 },
data: { title: 'Updated Title' }
}
}
}
})
```
### Update many related
```typescript
const user = await prisma.user.update({
where: { id: 1 },
data: {
posts: {
updateMany: {
where: { published: false },
data: { published: true }
}
}
}
})
```
### Upsert related
```typescript
const user = await prisma.user.update({
where: { id: 1 },
data: {
profile: {
upsert: {
create: { bio: 'New bio' },
update: { bio: 'Updated bio' }
}
}
}
})
```
### Disconnect
```typescript
// 1-to-1 optional
const user = await prisma.user.update({
where: { id: 1 },
data: {
profile: { disconnect: true }
}
})
// Many-to-many
const post = await prisma.post.update({
where: { id: 1 },
data: {
tags: {
disconnect: [{ id: 1 }, { id: 2 }]
}
}
})
```
### Delete related
```typescript
const user = await prisma.user.update({
where: { id: 1 },
data: {
posts: {
delete: { id: 1 }
}
}
})
// Delete many
const user = await prisma.user.update({
where: { id: 1 },
data: {
posts: {
deleteMany: { published: false }
}
}
})
```
### Set (replace all)
```typescript
// Replace all related records
const post = await prisma.post.update({
where: { id: 1 },
data: {
tags: {
set: [{ id: 1 }, { id: 2 }]
}
}
})
```
## Relation Filters
### some
At least one matches:
```typescript
const users = await prisma.user.findMany({
where: {
posts: { some: { published: true } }
}
})
```
### every
All match:
```typescript
const users = await prisma.user.findMany({
where: {
posts: { every: { published: true } }
}
})
```
### none
None match:
```typescript
const users = await prisma.user.findMany({
where: {
posts: { none: { published: true } }
}
})
```
### is / isNot (1-to-1)
```typescript
const users = await prisma.user.findMany({
where: {
profile: { is: { country: 'USA' } }
}
})
```
## Count Relations
```typescript
const users = await prisma.user.findMany({
select: {
name: true,
_count: {
select: { posts: true, followers: true }
}
}
})
// { name: 'Alice', _count: { posts: 5, followers: 100 } }
```
### Filter counted relations
```typescript
const users = await prisma.user.findMany({
select: {
name: true,
_count: {
select: {
posts: { where: { published: true } }
}
}
}
})
```
@@ -0,0 +1,184 @@
# Transactions
Execute multiple operations atomically.
## Sequential Transactions
Array of operations executed in order:
```typescript
const [user, post] = await prisma.$transaction([
prisma.user.create({ data: { email: 'alice@prisma.io' } }),
prisma.post.create({ data: { title: 'Hello', authorId: 1 } })
])
```
### All or nothing
If any operation fails, all are rolled back:
```typescript
try {
await prisma.$transaction([
prisma.user.create({ data: { email: 'alice@prisma.io' } }),
prisma.user.create({ data: { email: 'alice@prisma.io' } }) // Duplicate!
])
} catch (e) {
// Both operations rolled back
}
```
## Interactive Transactions
For complex logic and dependent operations:
```typescript
await prisma.$transaction(async (tx) => {
// Decrement sender balance
const sender = await tx.account.update({
where: { id: senderId },
data: { balance: { decrement: amount } }
})
// Check balance
if (sender.balance < 0) {
throw new Error('Insufficient funds')
}
// Increment recipient balance
await tx.account.update({
where: { id: recipientId },
data: { balance: { increment: amount } }
})
})
```
### Transaction options
```typescript
await prisma.$transaction(
async (tx) => {
// operations
},
{
maxWait: 5000, // Max wait to acquire lock (ms)
timeout: 10000, // Max transaction duration (ms)
isolationLevel: 'Serializable' // Isolation level
}
)
```
### Isolation levels
| Level | Description |
|-------|-------------|
| `ReadUncommitted` | Lowest isolation, can read uncommitted changes |
| `ReadCommitted` | Only read committed changes |
| `RepeatableRead` | Consistent reads within transaction |
| `Serializable` | Highest isolation, serialized execution |
## Nested Writes
Automatic transactions for nested operations:
```typescript
// This is automatically a transaction
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
posts: {
create: [
{ title: 'Post 1' },
{ title: 'Post 2' }
]
},
profile: {
create: { bio: 'Hello!' }
}
}
})
```
## Transaction Client
The `tx` parameter is a Prisma Client scoped to the transaction:
```typescript
await prisma.$transaction(async (tx) => {
// Use tx instead of prisma
await tx.user.create({ ... })
await tx.post.create({ ... })
// Can call methods
const count = await tx.user.count()
})
```
## OrThrow in Transactions
Use with interactive transactions:
```typescript
await prisma.$transaction(async (tx) => {
// If not found, throws and rolls back entire transaction
const user = await tx.user.findUniqueOrThrow({
where: { id: 1 }
})
await tx.post.create({
data: { title: 'New Post', authorId: user.id }
})
})
```
## Best Practices
### Keep transactions short
```typescript
// Good - only DB operations in transaction
const data = prepareData() // Outside transaction
await prisma.$transaction(async (tx) => {
await tx.user.create({ data })
})
```
### Handle errors
```typescript
try {
await prisma.$transaction(async (tx) => {
// operations
})
} catch (e) {
if (e.code === 'P2002') {
// Handle unique constraint violation
}
throw e
}
```
### Use appropriate isolation
```typescript
// Default is fine for most cases
await prisma.$transaction(async (tx) => {
// operations
})
// Use Serializable for strict consistency
await prisma.$transaction(
async (tx) => { /* operations */ },
{ isolationLevel: 'Serializable' }
)
```
## Sequential vs Interactive
| Feature | Sequential | Interactive |
|---------|------------|-------------|
| Syntax | Array | Async function |
| Dependent ops | No | Yes |
| Conditional logic | No | Yes |
| Performance | Better | More flexible |
| Use case | Simple batch | Complex logic |
@@ -0,0 +1,172 @@
---
name: prisma-compute
description: Deploy and operate apps on Prisma Compute with the Prisma 8 CLI. Use whenever the user mentions Prisma Compute, deploying or hosting a Prisma app, `prisma deploy`, `prisma dev module.ts`, Prisma Composer apps (`module.ts`, `compute()`, the `composer` section of `prisma.config.ts`), preview stages, deploy on push (`prisma git connect`, `prisma/cloud-deploy-action`), `prisma service` logs, versions, rollback, or custom domains, `project env`, `PRISMA_SERVICE_TOKEN`, regions, 504s, sleeping instances, or `waitUntil`; also when a project still uses the removed `@prisma/cli app deploy`, `prisma.compute.ts`, `defineComputeConfig`, `compute:deploy`, or `build logs` surface.
license: MIT
metadata:
author: prisma
version: "2.0.0"
---
# Prisma Compute
Deploy TypeScript apps to Prisma Compute and operate them afterwards. Every deploy goes through a Prisma Composer app (a `module.ts` root module) and the Prisma 8 CLI, `prisma`.
Verified against `prisma` 8.0.0-rc.21 (published identically as `@prisma/cli`), `@prisma/composer` and `@prisma/composer-prisma-cloud` 0.28.0, `@prisma/compute` 0.1.0-beta.0, and `create-prisma` 0.14.1. Re-checked against `prisma` 8.0.0-rc.23, whose command surface matches rc.21, and Composer 0.30.0, which adds `node()`'s `dependencies` option (0.29.0) and narrows the supported Node.js versions. The CLI moves fast: run `npx prisma <group> --help` before using a flag this skill does not show.
## Version-Matched Skills
The installed packages ship their own agent skills, matched to the installed version:
- `prisma-platform-core-concepts`, inside `prisma`: projects, branches, services, versions, env vars, deploy on push.
- `prisma-composer-core-concepts`, inside `@prisma/composer`: declaring services, modules, databases, and builds; `dev`, `deploy`, and teardown.
`npx prisma skills sync` copies them into the agent skill directories (`.claude/skills`, `.cursor/skills`, `.agents/skills`, `.devin/skills`), and `npx prisma skills list` shows what is installed. `npx prisma init` does the same and adds a `postinstall` hook that keeps them current. When those skills are installed, use them for API details. This skill covers the deploy and operations workflow and its pitfalls.
## Removed Surface
The Compute CLI from before Composer is gone. Its commands fail with `CLI.UNKNOWN_COMMAND` (removed flags with `CLI.INVALID_ARGUMENTS`), its config files are not read, and its environment variables are ignored:
| Removed | Use instead |
|---------|-------------|
| `@prisma/cli app deploy`, `app build`, `app run` | Your own build script, then `npx prisma deploy module.ts`; `npx prisma dev module.ts` to run locally |
| `prisma.compute.ts`, `prisma.compute.json`, `defineComputeConfig` | `module.ts`, a `service.ts` per server declared with `compute()`, and the `composer` section of `prisma.config.ts` |
| `init` writing a compute config | `npx prisma init` now writes a `prisma.config.ts` with only a `skills` section, adds `prisma` as a dev dependency, and syncs skills. Add the `composer` section yourself |
| `compute:deploy` script | `npx prisma deploy module.ts`, or the `deploy` script current `create-prisma` generates |
| `app deploy --branch <name>` | `npx prisma deploy module.ts --stage <name>` |
| `app deploy --prod`, `--no-promote`, `app promote` | No `--stage` deploys production; `service version promote <version-id>` |
| `app show`, `app open`, `app list-deploys`, `app show-deploy` | `service show <service>`, `service open <service>`, `service version list <service>`, `service version show <version-id>` |
| `app logs` | `service logs <service>` |
| `app rollback --to <id> --yes` | `service version rollback <service> --to <id> --confirm <id>` |
| `app domain ...` | `service domain ... --service <service>` |
| `app remove` | Remove the `provision()` from `module.ts` and deploy, or `service delete <service> --confirm <service>` |
| `build logs <build-id>` | The GitHub Actions run log or the Console; `GET /v1/builds/{buildId}` for state and failing step |
| `database ...` | `postgres ...` |
| `project env remove` | `project env delete` |
| `auth logout --workspace <id>` | `auth workspace logout <id>` |
| `agent install`, `agent update`, `agent status` | `npx skills add prisma/skills --skill prisma-compute`; `npx prisma skills sync` for package skills |
| `PRISMA_PROJECT_ID`, `PRISMA_APP_ID`, `PRISMA_SERVICE_ID` | `--project <id-or-name>`, the service as a positional argument, and `.prisma/local.json` from `project link` |
| `/v1/apps` REST endpoints | `/v1/services` (the `/v1/apps` paths are deprecated) |
A repository with `prisma.compute.ts` or a `compute:deploy` script was set up for the removed flow. Port it to Composer ([`app-composer-setup.md`](references/app-composer-setup.md)) instead of running the old commands.
## When to Apply
- Deploying a new or existing app to Prisma Compute
- Porting a project that uses `prisma.compute.ts`, `compute:deploy`, or `@prisma/cli app deploy`
- Setting up preview stages, deploy on push, or CI deploys
- Reading service logs, listing versions, promoting, or rolling back
- Managing env vars, custom domains, Prisma Postgres databases, or buckets in a Compute project
- Debugging a failed deploy, an unreachable service, a `504`, or work that stops when an instance sleeps
## Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | CLI surface | CRITICAL | `cli-` |
| 2 | App declaration | CRITICAL | `app-` |
| 3 | Runtime | CRITICAL | `runtime-` |
| 4 | Deploy | HIGH | `deploy-` |
| 5 | Operations | HIGH | `ops-` |
| 6 | Debugging | HIGH | `debug-` |
| 7 | Automation | MEDIUM | `automation-` |
## Quick Reference
### 1. CLI surface (CRITICAL)
- `cli-prisma-8-binary` - Platform and deploy commands exist only in the Prisma 8 CLI. In a Prisma 6 or 7 project, `npx prisma` runs that version's ORM CLI, which has no `auth`, `project`, `service`, or `deploy`; Prisma 7's `dev` starts a local database instead. Check `npx prisma --version`; outside a Prisma 8 project use `npx @prisma/cli@latest <command>`.
- `cli-help-first` - Command groups are `auth`, `project` (with `project env`), `postgres`, `bucket`, `branch`, `git`, and `service` (with `service version` and `service domain`), plus `deploy`, `dev`, `init`, `skills`, and `feedback`. Read `--help` before using a flag.
- `cli-json` - Pass `--json`, and `--no-interactive` in scripts. Branch on `error.code` (`NAMESPACE.SUBCODE`) and follow `nextActions`; do not parse messages.
- `cli-explicit-targets` - Name the service as the first argument, the project with `--project` (or link the directory), and a preview with `--branch`. Without `--branch` a command targets the production branch; the CLI does not read the current Git branch.
- `cli-consent-tokens` - Destructive commands need `--confirm <token>` with an exact id, name, or hostname. `--yes` cannot grant consent. Run them only when the user asked for that action.
### 2. App declaration (CRITICAL)
- `app-composer-required` - A deployable app has `module.ts` (default export `module(name, ...)`), a `service.ts` per server (`compute({ name, deps, build })`), and a `composer` section in `prisma.config.ts` with `prismaCloud()`, `nodeBuild()` (plus `nextjsBuild()` for Next.js), and `state: prismaState()`.
- `app-build-adapter` - `node({ module: import.meta.url, entry })` for one self-contained bundle, `node({ module, dir, entry })` for a built directory, `nextjs({ module, appDir })` for Next.js standalone. Add `dependencies: "external"` to `node()` when the build leaves packages as imports. See [`app-framework-builds.md`](references/app-framework-builds.md).
- `app-region` - The first deploy creates the project and needs a region: `prismaCloud({ region: "eu-central-1" })` or `PRISMA_REGION`. The region cannot change later.
- `app-databases` - `rawPostgres()` (package root) delivers `{ url }`; `postgres(contract)` from `@prisma/composer-prisma-cloud/orm` adds a typed client and applies committed migrations on deploy. Read both through `service.load()`, not `process.env.DATABASE_URL`.
- `app-names` - Provision ids and service names allow `[A-Za-z0-9]` only, and the platform rejects ids shorter than three characters. The root module name becomes the project name.
### 3. Runtime (CRITICAL)
- `runtime-bind-all-interfaces` - Listen on `service.port()` (also exported as `PORT`, default 3000) and bind `0.0.0.0`. A loopback listener is unreachable.
- `runtime-bun` - Services run on Bun. By default (`dependencies: "bundled"`) a deploy ships only the build output, never the project's `node_modules`, so the build must inline every dependency except runtime built-ins. A build that leaves packages as imports (`tsc`, Astro's Node adapter) sets `dependencies: "external"` on `node()`, and the deploy stages the installed packages its entry imports.
- `runtime-first-byte-60s` - A request that sends no bytes for 60 seconds gets `504 Gateway Time-out` and is cancelled. Respond first, then continue under `waitUntil` or from a queue.
- `runtime-sleep` - Idle instances are snapshotted and resumed. Timers and floating promises can stall. `waitUntil` and `KeepAwakeGuard` from `@prisma/compute` keep an instance awake on a best-effort basis; they do not make work durable.
- `runtime-no-websockets` - WebSocket servers are not supported.
### 4. Deploy (HIGH)
- `deploy-build-first` - `deploy` and `dev` do not build. Run the build, then `npx prisma deploy module.ts`.
- `deploy-dev-first` - `npx prisma dev module.ts` runs the whole app locally with no credentials. Verify each local URL before deploying.
- `deploy-production-intent` - A deploy without `--stage`, and a push to the default branch of a connected repository, change production. Get the user's go-ahead first; use `--stage <name>` for previews.
- `deploy-auth` - On a workstation the user runs `npx prisma auth login` (browser). In CI set `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID`. Check `npx prisma auth whoami --json` (`envelope.result.authenticated`, `envelope.result.workspace`) before deploying.
- `deploy-link-after` - `deploy` finds or creates the project by the root module name (or `--name`) and does not write `.prisma/local.json`. Run `npx prisma project link <app-name>` afterwards, or pass `--project`, before `service`, `git`, or `project env` commands.
- `deploy-on-push` - Deploy on push needs both `npx prisma git connect` (interactive) and a workflow running `prisma/cloud-deploy-action@v1`. Connecting alone deploys nothing.
- `deploy-verify-url` - Take each service URL from the deploy output (`--json` result or `--report <path>`) and request it.
### 5. Operations (HIGH)
- `ops-logs` - `service logs <service>` reads the live version; `--version-id <id>` reads another, `--follow` streams. Build output lives in the CI log or the Console, not the CLI.
- `ops-versions` - `service version promote <version-id>` rebuilds with production env vars. `service version rollback <service> --to <id> --confirm <id>` switches back without a rebuild.
- `ops-env-write-only` - `project env add|update|list|delete` with `--role production`, `--role preview`, or `--branch <name>`. Values are never returned and apply on the next deploy.
- `ops-domains` - `service domain add <hostname> --service <service>`, create the CNAME it reports, then `service domain wait`. Production branch only.
- `ops-secrets-once` - `postgres create`, `postgres connection create|rotate`, and `bucket key create` print credentials once. Store them; never echo them.
### 6. Debugging (HIGH)
- `debug-error-code-first` - Read `error.code` and `nextActions` from `--json` output, or `failure.code` from the `--report` file, before changing anything.
- `debug-public-url` - Test the printed public URL, not `localhost`. A deploy that converged but does not answer is usually host binding, the port, or a crash at boot; read `service logs`.
- `debug-report-cli-bugs` - Report unresolvable CLI failures with `npx prisma feedback "<message>"` without secrets.
### 7. Automation (MEDIUM)
- `automation-create-prisma` - `create-prisma` scaffolds a new Prisma 8 project that is already a Composer app. Its `--json` mode deploys unless `--no-deploy` is passed.
- `automation-control-api` - `@prisma/composer/control` exposes `deploy`, `destroy`, `dev`, and `log`. Teardown of a stage is `destroy`; it reads only `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID`.
- `automation-rest-api` - Use `/v1/services`, `/v1/deployments/{deploymentId}/logs`, and `/v1/builds` from `https://api.prisma.io/v1/doc`. Do not build new deploy tooling on `@prisma/compute-sdk`.
## Preferred Workflow
1. Inspect `package.json` (is `prisma` 8.x a dev dependency, are `@prisma/composer` and `@prisma/composer-prisma-cloud` installed?), `module.ts`, `prisma.config.ts`, the build script, and leftovers from the removed flow (`prisma.compute.ts`, `compute:deploy`).
2. Install what is missing and sync the package skills:
```bash
npm install @prisma/composer @prisma/composer-prisma-cloud
npm install -D prisma
npx prisma skills sync
```
3. Declare or port the app: [`app-composer-setup.md`](references/app-composer-setup.md) and [`app-framework-builds.md`](references/app-framework-builds.md).
4. Build, run `npx prisma dev module.ts`, and request each local URL it prints.
5. Run `npx prisma auth whoami --json`. If `envelope.result.authenticated` is `false`, ask the user to run `npx prisma auth login`.
6. Deploy a preview with `npm run build && npx prisma deploy module.ts --stage <name> --json`, or production without `--stage` once the user confirms. A new project needs a region.
7. Request each printed URL, then `npx prisma project link <app-name>` and `npx prisma service list --json` (add `--branch <stage>` for a preview).
8. Report the app name, stage, service ids, URLs, and database ids. Never report secret values.
## Avoid
- Do not run `@prisma/cli app ...`, `build logs`, or `database ...`, and do not create `prisma.compute.ts`.
- Do not run platform commands through a Prisma 6 or 7 `prisma` binary.
- Do not read the port or connection strings from `process.env` in a Composer service.
- Do not expect `deploy` to build, to migrate a `rawPostgres()` database, or to copy production data into a stage.
- Do not pass `--yes` to destructive commands; it cannot grant consent.
- Do not run `auth login` or `git connect` non-interactively; both need a person at a browser.
- Do not push to the default branch of a connected repository without the user's go-ahead; it deploys production.
## References
- [`cli-command-map.md`](references/cli-command-map.md): every verified command, global flags, JSON envelope, targeting, consent tokens
- [`app-composer-setup.md`](references/app-composer-setup.md): the minimum declaration, region, databases, config and secrets, porting from `prisma.compute.ts`
- [`app-framework-builds.md`](references/app-framework-builds.md): build output and `build:` adapter per framework
- [`runtime-requirements.md`](references/runtime-requirements.md): Bun, host and port, 60-second first byte, sleep, keep-awake, regions
- [`deploy-cli-and-ci.md`](references/deploy-cli-and-ci.md): `prisma deploy`, stages, credentials, output, CI, teardown
- [`deploy-on-push.md`](references/deploy-on-push.md): GitHub connection and the `prisma/cloud-deploy-action` workflow
- [`ops-services-and-config.md`](references/ops-services-and-config.md): services, versions, logs, domains, env vars, databases, buckets
- [`debug-deploy-failures.md`](references/debug-deploy-failures.md): symptoms, causes, and fixes
- [`automation-create-prisma.md`](references/automation-create-prisma.md): scaffolding a new Composer app
- [`automation-rest-api.md`](references/automation-rest-api.md): REST API paths, the control API, and the status of `@prisma/compute-sdk`
Docs: [Compute](https://www.prisma.io/docs/compute), [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy), [Composer](https://www.prisma.io/docs/composer), [CLI reference](https://www.prisma.io/docs/cli).
## Feedback
`npx prisma feedback "<message>"` sends anonymous feedback to the CLI team with the CLI version, Node.js version, and OS platform. Add `--email <address>` for a reply. Never include tokens, connection URLs, or user data.
@@ -0,0 +1,189 @@
# app-composer-setup
Compute deploys only Prisma Composer apps: a root module, one service declaration per server, and a `composer` section in `prisma.config.ts`.
## Priority
CRITICAL
## Why It Matters
`prisma deploy` takes a module file, not a framework name or a config file. Without `module.ts`, a `compute()` service, and the `composer` config section, there is nothing to deploy. This file covers the minimum an agent needs. For contracts between services, input schemas, modules, and testing, use the `prisma-composer-core-concepts` skill and the [Composer docs](https://www.prisma.io/docs/composer).
## Requirements
- Node.js 22.18 or newer on the 22 line, 24.11 or newer on the 24 line, or 26 or newer (`engines.node` is `^22.18.0 || ^24.11.0 || >=26.0.0` since Composer 0.30.0). Composer loads the `.ts` entry directly; older versions stop at `ERR_UNKNOWN_FILE_EXTENSION`.
- Bun. Deployed services run on Bun, and `bun build --target=bun` is the simplest way to produce the single-file entry a service needs.
- The packages:
```bash
npm install @prisma/composer @prisma/composer-prisma-cloud
npm install -D prisma
npx prisma skills sync
```
`@prisma/composer` pins its own `effect` version; do not add a different `effect` to the app. See [`debug-deploy-failures.md`](debug-deploy-failures.md) if `prisma.config.ts` fails to evaluate.
## The Four Files
```ts
// src/server.ts
import service from "./service.ts";
Bun.serve({
port: service.port(),
hostname: "0.0.0.0",
fetch: () => new Response("ok"),
});
```
```ts
// src/service.ts
import node from "@prisma/composer/node";
import { compute } from "@prisma/composer-prisma-cloud";
export default compute({
name: "web",
deps: {},
build: node({ module: import.meta.url, entry: "../dist/server.mjs" }),
});
```
```ts
// module.ts
import { module } from "@prisma/composer";
import web from "./src/service.ts";
export default module("my-app", ({ provision }) => {
provision(web);
});
```
```ts
// prisma.config.ts
import { defineConfig as composer } from "@prisma/composer/config";
import { nodeBuild } from "@prisma/composer/node/control";
import { prismaCloud, prismaState } from "@prisma/composer-prisma-cloud/control";
import { definePrismaConfig } from "prisma/config";
export default definePrismaConfig({
composer: composer({
extensions: [prismaCloud({ region: "us-east-1" }), nodeBuild()],
state: prismaState(),
}),
});
```
And a build script in `package.json` that produces the file `entry` points at:
```json
{
"scripts": {
"build": "bun build src/server.ts --target=bun --outfile dist/server.mjs"
}
}
```
Rules:
- `entry` and `dir` resolve relative to the service module (`module: import.meta.url`), not the project root.
- The `composer` section accepts only `extensions` and `state`. Add `nextjsBuild()` from `@prisma/composer/nextjs/control` when a service uses the `nextjs` adapter.
- `prisma.config.ts` is read by the CLI only; app code never imports it. A separate `prisma-composer.config.ts` is refused.
- Inside the module graph, write relative imports with explicit `.ts` extensions and enable `allowImportingTsExtensions` in `tsconfig.json`.
## Region
The first deploy creates the project and needs a region. Set `prismaCloud({ region })` or `PRISMA_REGION`; the config value wins when both are set. Without either, the deploy stops with `project "<name>" does not exist yet and no deploy region is configured`. Once the project exists it keeps its region, and stages inherit it.
Region ids: `us-east-1`, `us-west-1`, `eu-west-3`, `eu-central-1`, `ap-northeast-1`, `ap-southeast-1`.
## Names
- The root module name (`module("my-app", ...)`) becomes the project name and may contain hyphens. `deploy --name <name>` overrides it.
- `compute({ name })` and `provision()` ids allow `[A-Za-z0-9]` only. A hyphenated id passes `tsc` and then fails at load. The platform rejects provision ids shorter than three characters, so name a database `database`, not `db`.
## Databases
Declare the database as a dependency of the service and provision it in the module that owns it. The service reads the value with `service.load()`.
```ts
// src/service.ts
import node from "@prisma/composer/node";
import { compute, rawPostgres } from "@prisma/composer-prisma-cloud";
export default compute({
name: "api",
deps: { db: rawPostgres() },
build: node({ module: import.meta.url, entry: "../dist/server.mjs" }),
});
```
```ts
// module.ts
import { module } from "@prisma/composer";
import { rawPostgres } from "@prisma/composer-prisma-cloud";
import api from "./src/service.ts";
export default module("my-app", ({ provision }) => {
const db = provision(rawPostgres({ name: "database" }));
provision(api, { deps: { db } });
});
```
```ts
// src/server.ts
import { SQL } from "bun";
import service from "./service.ts";
const { db } = service.load();
const sql = new SQL({ url: db.url, max: 1, idleTimeout: 10 });
```
- `rawPostgres()` comes from the package root and delivers `{ url }`. You own the client and the schema; the deploy runs no migrations for it.
- `postgres(contract)` comes from `@prisma/composer-prisma-cloud/orm`, together with `dataContract`. It delivers `{ url, client }` with a client typed by your Prisma ORM data contract, and the deploy applies the committed `migrations/` before the service starts. Every schema change goes through `prisma contract emit` and `prisma migration plan` first. See [Databases](https://www.prisma.io/docs/composer/databases).
- `postgres` is not exported from the package root in 0.28.0, and `postgres()` with no argument does not declare a plain database. Use `rawPostgres()` for that.
- Each stage gets its own empty databases. Production data is never copied.
Buckets work the same way: `bucket()` from the package root, delivering `{ url, bucket, accessKeyId, secretAccessKey }`.
## Configuration and Secrets
Composer services do not read `process.env`. Declare the service's configuration as an input schema, and bind each field at `provision()` to a literal, `envParam("NAME")`, or `envSecret("NAME")`. The named values live in the stage's platform environment variables (`project env`). A deploy copies a missing name from the deploying shell and fails early, naming the variable, when neither has it. See [Service input](https://www.prisma.io/docs/composer/service-input).
## Porting From `prisma.compute.ts`
| `prisma.compute.ts` field | Composer equivalent |
|---------------------------|---------------------|
| `app.name` / `apps.<key>` | `compute({ name })`; the root module name is the project name |
| `framework`, `build.command` | Your own `build` script, run before `deploy` |
| `entry`, `build.outputDirectory`, `build.entrypoint` | `node({ module, entry })` or `node({ module, dir, entry })` pointing at built output, or `nextjs({ module, appDir })` |
| `httpPort` | Removed. Listen on `service.port()` |
| `env` file | Platform env vars through `project env add --file`, bound with `envParam`/`envSecret`; a database becomes a declared dependency |
| `region` | `prismaCloud({ region })`, used only when the first deploy creates the project |
| `apps` (monorepo) | One `compute()` per deployable app, all provisioned in one `module.ts` |
| `--branch <name>` on deploy | `deploy --stage <name>` |
Then delete `prisma.compute.ts`, the `compute:deploy` script, and the `@prisma/compute-sdk` dev dependency if nothing else imports it. `.prisma/cli/state.json` from the old CLI is no longer used.
## Bad
```ts
// prisma.compute.ts
import { defineComputeConfig } from "@prisma/compute-sdk/config";
export default defineComputeConfig({
app: { framework: "hono", entry: "src/index.ts", httpPort: 8080 },
});
```
No current command reads this file.
## Good
`module.ts`, `src/service.ts`, and the `composer` section of `prisma.config.ts` as shown above, with a build script that writes the file `entry` names.
## References
- [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy)
- [Port an existing app](https://www.prisma.io/docs/composer/porting-an-app)
- [Composer getting started](https://www.prisma.io/docs/composer/getting-started)
@@ -0,0 +1,75 @@
# app-framework-builds
Each framework deploys through a build adapter in its `service.ts` that points at the output your own build produced.
## Priority
CRITICAL
## Why It Matters
Neither `prisma deploy` nor the deploy action detects a framework or runs a build. The service declaration names the built output, and a mismatch between it and what the build writes fails at assemble time or at boot. There are no framework keys any more (`--framework nextjs` and similar belonged to the removed CLI).
## Adapters
| Adapter | Import | Use for |
|---------|--------|---------|
| `node({ module: import.meta.url, entry })` | `@prisma/composer/node` | One self-contained ESM file with every dependency inlined except runtime built-ins (`bun`, `bun:*`, `node:*`) |
| `node({ module: import.meta.url, dir, entry })` | `@prisma/composer/node` | A built directory copied as-is; `entry` is a file inside `dir` |
| `nextjs({ module: import.meta.url, appDir })` | `@prisma/composer/nextjs` | A Next.js app built with `output: "standalone"`; add `nextjsBuild()` to the `composer` extensions |
| `dependencies: "external"` on either `node()` form | `@prisma/composer/node` | A build that leaves packages as imports. The deploy traces `entry` and stages the installed packages it imports, which can take minutes. Composer 0.29.0 and later |
Paths are relative to the service module. With the default `dependencies: "bundled"`, the deploy copies only what the build produced and never ships the project's `node_modules`, for a single file and for a `dir` build alike, so a package left as an import fails at boot with `Cannot find package`. Bundle it, or set `dependencies: "external"`. A `dir` tree must contain no symlinks and `entry` must not leave `dir`. Two services in one package need two separate builds, one per entry.
## Per Framework
The shapes `create-prisma` 0.14.1 generates, with `service.ts` at the project root:
| Framework | Build script | `build:` in `service.ts` | Requirements |
|-----------|--------------|--------------------------|--------------|
| Hono, Elysia, NestJS, plain server | Bundle to one file (`bun build src/index.ts --target=bun --outfile dist/server.mjs`, or tsdown bundling every non-built-in dependency) | `node({ module: import.meta.url, entry: "./dist/server.mjs" })` | The entry starts the HTTP server itself |
| Next.js | `next build` | `nextjs({ module: import.meta.url, appDir: "." })` | `output: "standalone"` in `next.config.*`; `nextjsBuild()` in `prisma.config.ts` |
| Nuxt | `nuxt build` | `node({ module: import.meta.url, dir: "./.output", entry: "server/index.mjs" })` | Default Nitro Node server preset |
| TanStack Start | `vite build` | `node({ module: import.meta.url, dir: "./.output", entry: "server/index.mjs" })` | `nitro()` from `nitro/vite` in the Vite plugins |
| Astro | `astro build` | `node({ module: import.meta.url, dir: "./dist", entry: "server/entry.mjs", dependencies: "external" })` | `output: "server"`, `adapter: node({ mode: "standalone" })` from `@astrojs/node`. The adapter leaves packages as imports, so Composer 0.29.0 and later need `dependencies: "external"`; `create-prisma` 0.14.x pins Composer 0.28.0 and omits it |
| SvelteKit | `vite build` | `node({ module: import.meta.url, dir: "./build", entry: "index.js" })` | `@sveltejs/adapter-node`, with `ssr: { noExternal: true }` in `vite.config.ts` so the build inlines packages; without it, add `dependencies: "external"` |
| Turborepo | `turbo run build` | `node({ module: import.meta.url, entry: "./apps/server/dist/server.mjs" })` | One `compute()` per deployable app |
Verify the actual output path after a local build before writing `entry` or `dir`.
## Host and Port
The runtime exports the reserved port as `PORT` and sets `HOST` to `0.0.0.0` when it is unset. Code you write reads `service.port()` and binds `0.0.0.0`. Framework servers that read `PORT` themselves (Next.js standalone, Nitro, Astro's Node adapter, SvelteKit's Node adapter) work without changes. Never set `HOST` or `HOSTNAME` to `localhost` or `127.0.0.1` in deploy env.
```ts
// Elysia
app.listen({ port: service.port(), hostname: "0.0.0.0" });
// NestJS
await app.listen(service.port(), "0.0.0.0");
```
## Next.js Pages That Read the Service
A page, route handler, or server action that calls `service.load()` or `service.input()` needs `export const dynamic = "force-dynamic"`. The runtime environment does not exist at build time, and Next.js does not re-read it for prerendered routes.
## Bad
```ts
build: node({ module: import.meta.url, entry: "./src/index.ts" }),
```
The entry is source, not a self-contained build. Imports from `node_modules` fail at boot.
## Good
```ts
build: node({ module: import.meta.url, entry: "./dist/server.mjs" }),
```
with `"build": "bun build src/index.ts --target=bun --outfile dist/server.mjs"`.
## References
- [Port an existing app](https://www.prisma.io/docs/composer/porting-an-app)
- [Framework guides](https://www.prisma.io/docs/guides)
@@ -0,0 +1,89 @@
# automation-create-prisma
`create-prisma` scaffolds a new Prisma 8 project that is already a Composer app, and can deploy it once.
## Priority
MEDIUM
## Why It Matters
`create-prisma` writes a working Composer app in one command, but only for new projects, and its `--json` mode deploys by default. Older versions generated `prisma.compute.ts` and a `compute:deploy` script; current versions generate `module.ts`, `service.ts`, and a `composer` section instead.
Verified with `create-prisma` 0.14.1.
## Commands
```bash
npx create-prisma@latest --help
```
| Flag | Meaning |
|------|---------|
| `[project-name]`, `--name` | Project directory and root module name |
| `--template` | `minimal`, `hono`, `elysia`, `nest`, `next`, `turborepo`, `svelte`, `astro`, `nuxt`, `tanstack-start` |
| `--provider` | `postgres` or `mongo` |
| `--authoring` | `psl` or `typescript` for the data contract |
| `--package-manager` | `npm`, `pnpm`, `yarn`, `bun`, `deno` |
| `--deploy` | Build and deploy after scaffolding |
| `--workspace` | Workspace id or name to deploy into |
| `--skills` | Agents to install package skills for (`claude,cursor,agents,devin`), or `none` |
| `--yes` | Accept defaults; does not deploy |
| `--json` | One JSON result, non-interactive; deploys unless `--no-deploy` |
When to deploy:
| Invocation | Deploys |
|------------|---------|
| `--deploy` | Yes |
| `--json` without `--no-deploy` | Yes |
| `--yes` without `--deploy` or `--json` | No |
| Interactive | Asks |
| `--package-manager deno` | Never; no Composer files are generated |
For an unattended scaffold with no deploy, pass both:
```bash
npx create-prisma@latest my-api --template hono --provider postgres --yes --json --no-deploy
```
## What It Generates
- `module.ts` provisioning one service named `app`. With `--provider postgres`, it also provisions `postgres({ name: "database", contract, config: "./prisma.config.ts" })` from `@prisma/composer-prisma-cloud/orm`, so the deploy applies the generated migrations. With `--provider mongo`, it binds `envSecret("MONGODB_URL")` to the service input.
- `service.ts` with the build adapter for the template; see [`app-framework-builds.md`](app-framework-builds.md).
- `prisma.config.ts` with `orm`, `skills`, and `composer` sections. The `composer` section uses `prismaCloud({ region: "us-east-1" })`; change the region before the first deploy if the app belongs elsewhere.
- Scripts: `composer:dev` (`prisma dev module.ts`), `composer:deploy` (`prisma deploy module.ts`), `dev:composer` (build, then `composer:dev`), and `deploy` (build, then `composer:deploy`). The `deploy` script targets production; pass a stage with `npx prisma deploy module.ts --stage <name>` instead.
- `/.prisma-composer` in `.gitignore`.
## Deploy Flow
With deploy enabled, `create-prisma` runs `prisma auth whoami`, selects the workspace, checks that no project already has the app's name, runs the build script, and runs `prisma deploy module.ts --report <tmp>`. Without a session it signs in interactively in a terminal; in `--json` mode or without a TTY it stops with `not_authenticated`, keeps the scaffold, and tells the user to sign in and run the `deploy` script.
## Rules
- Do not run `create-prisma` inside an existing app to deploy it. Port the app ([`app-composer-setup.md`](app-composer-setup.md)) and use `prisma deploy`.
- Use the scripts the scaffold actually wrote; read `package.json` rather than reconstructing them.
- A scaffold's first deploy is production. Ask the user before using `--deploy` or `--json` without `--no-deploy`.
## Bad
```bash
npx create-prisma@latest my-api --template hono --yes --json
```
This deploys to production without anyone deciding to.
## Good
```bash
npx create-prisma@latest my-api --template hono --provider postgres --yes --json --no-deploy
cd my-api
npm run dev:composer
```
Verify locally, then deploy a stage with `npm run build && npx prisma deploy module.ts --stage preview`.
## References
- [create-prisma on npm](https://www.npmjs.com/package/create-prisma)
- [Deploy your first app](https://www.prisma.io/docs/prisma-compute/deploy)
@@ -0,0 +1,99 @@
# automation-rest-api
Programmatic access to Compute: the Management REST API, the Composer control API, and what became of `@prisma/compute-sdk`.
## Priority
MEDIUM
## Why It Matters
Deploys now go through Composer, so low-level deploy clients from the earlier flow create resources that no `module.ts` declares. Use the CLI or the control API to deploy, and the REST API to read state, stream logs, and integrate with other tools.
## Choose the Surface
| Goal | Use |
|------|-----|
| Deploy or tear down an app | `prisma deploy`, or `deploy`/`destroy` from `@prisma/composer/control` |
| Deploy from GitHub | `prisma/cloud-deploy-action` ([`deploy-on-push.md`](deploy-on-push.md)) |
| Read services, versions, builds, logs from your own tool | REST API |
| A coding agent with its own credential and approval policy | [Agent enrollment](https://www.prisma.io/docs/prisma-compute/agent-enrollment) (REST API) |
## REST API
Base URL `https://api.prisma.io/v1`. The current OpenAPI document is at `https://api.prisma.io/v1/doc`; read it for exact payloads instead of copying shapes from memory. Authenticate with `Authorization: Bearer <workspace service token>` or an OAuth token. The Compute endpoints are marked experimental and can change.
| Resource | Paths |
|----------|-------|
| Projects | `GET/POST /v1/projects`, `GET/PATCH/DELETE /v1/projects/{id}` |
| Branches | `GET/POST /v1/projects/{projectId}/branches` (`gitName` filter), `GET/PATCH/DELETE /v1/branches/{branchId}` |
| Services | `GET/POST /v1/services` (filter by `projectId`, `branchId`, `branchGitName`), `GET/PATCH/DELETE /v1/services/{serviceId}` |
| Versions (deployments) | `GET/POST /v1/services/{serviceId}/deployments`, `GET/DELETE /v1/deployments/{deploymentId}`, `POST /v1/deployments/{deploymentId}/start`, `POST /v1/deployments/{deploymentId}/stop` |
| Promote and rollback | `POST /v1/services/{serviceId}/promote`, `POST /v1/services/{serviceId}/rollback` |
| Logs | `GET /v1/deployments/{deploymentId}/logs` |
| Builds | `GET/POST /v1/builds` (filter by `projectId`, `branchId`, `state`), `GET/PATCH /v1/builds/{buildId}` |
| Domains | `GET/POST /v1/services/{serviceId}/domains`, `GET/DELETE /v1/domains/{domainId}`, `POST /v1/domains/{domainId}/retry` |
| Environment variables | `GET/POST /v1/environment-variables` (filter by `projectId`, `class`, `key`, `branchId`), `GET/PATCH/DELETE /v1/environment-variables/{envVarId}` |
The `/v1/apps` paths (`/v1/apps`, `/v1/apps/{appId}/deployments`, `/promote`, `/rollback`, `/domains`) are deprecated. Use the `/v1/services` equivalents.
### Logs
`GET /v1/deployments/{deploymentId}/logs` takes `tail`, `from_start`, or `cursor`. A plain GET returns newline-delimited JSON: `type: "log"` records, then a `type: "terminal"` record carrying the cursor for the next page. Send `Upgrade: websocket` to follow live; a live segment ends after 10 minutes with the same terminal record, so reconnect with the cursor.
### Builds
A build record is what a deploy reports about itself: the deploy action and `prisma deploy` both write to it. `GET /v1/builds/{buildId}` returns its `state`, `failingStep`, `errorMessage`, `externalLogUrl` (for example the GitHub Actions run), and `deployedUrl`. There is no build log endpoint; the log lives at `externalLogUrl` or in the terminal that ran the deploy. `prisma deploy --build-id <id>` joins a build record your CI created with `POST /v1/builds`.
### Secrets
Environment variable values are write-only: no endpoint returns them. Do not log tokens, connection URLs, or env values.
## Control API
`@prisma/composer/control` runs the CLI's operations in-process and returns `{ ok: true, value }` or `{ ok: false, failure }` with a dotted `failure.code`:
```ts
import { deploy } from "@prisma/composer/control";
import prismaConfig from "./prisma.config.ts";
const result = await deploy({
entry: "module.ts",
config: { value: prismaConfig.composer, file: "prisma.config.ts" },
stage: "pr-42",
});
if (!result.ok) throw new Error(`${result.failure.code}: ${result.failure.message}`);
```
- Operations: `deploy`, `destroy`, `dev`, `log`. `config` is required in 0.28.0.
- `deploy` and `destroy` read only `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID`, never the `auth login` session. Without them they fail with `environment variable PRISMA_WORKSPACE_ID is required`.
- `log` tails a locally running `prisma dev` app; it is not a platform log reader.
- The engine's own output still streams to stdio.
## `@prisma/compute-sdk`
`@prisma/compute-sdk` 0.43.0 is still on npm, and the CLI uses it internally for service operations and log streaming. Its `deploy()` build strategies and `defineComputeConfig` belong to the removed flow: no CLI command reads `prisma.compute.ts`, and its app client calls the deprecated `/v1/apps` endpoints. Do not start new deploy automation on it, and remove it from projects that used it only for `defineComputeConfig`.
## Bad
```ts
import { ComputeClient, PreBuilt } from "@prisma/compute-sdk";
await new ComputeClient(apiClient).deploy({
strategy: new PreBuilt({ appPath: "./dist", entrypoint: "index.js" }),
projectId: "proj_abc",
appName: "my-app",
});
```
This creates an app outside any Composer declaration, through deprecated endpoints.
## Good
Deploy with `prisma deploy module.ts` or the control API, and read the result back with `GET /v1/services?projectId=...` and `GET /v1/deployments/{deploymentId}/logs`.
## References
- [REST API](https://www.prisma.io/docs/rest-api)
- [OpenAPI document](https://api.prisma.io/v1/doc)
- [`deploy` command and control API](https://www.prisma.io/docs/cli/deploy)
@@ -0,0 +1,137 @@
# cli-command-map
The Prisma 8 CLI commands an agent uses to deploy and operate a Compute app, with the flags, output, and targeting rules that matter.
## Priority
CRITICAL
## Why It Matters
Agents trained on the earlier Compute CLI reach for `@prisma/cli app deploy`, `build logs`, and `database ...`, which no longer exist. The current CLI also refuses to guess: it needs explicit targets, exact consent tokens for destructive actions, and the Prisma 8 binary.
Verified with `prisma` 8.0.0-rc.21 and `@prisma/cli` 8.0.0-rc.21 (same commands; the `@prisma/cli` binary is named `prisma-cli`).
## Which Binary Runs
| Situation | Run |
|-----------|-----|
| Composer app with `prisma` 8.x in `devDependencies` | `npx prisma <command>` (or `bunx prisma`, `pnpm exec prisma`) |
| No local `prisma`, or a Prisma 6/7 project | `npx @prisma/cli@latest <command>` |
A Prisma 6 or 7 `prisma` binary has no `auth`, `project`, `service`, `branch`, `git`, or `deploy` commands. In Prisma 7, `dev` starts a local Prisma Postgres server and `postgres` only links an existing database. `npx prisma --version` prints the version; in a non-terminal it prints a JSON envelope with `result.version`.
## Commands
| Command | Subcommands and flags | Notes |
|---------|-----------------------|-------|
| `auth` | `login`, `logout`, `whoami`, `workspace list`, `workspace use [id-or-name]`, `workspace logout <id-or-name>` | `login` opens a browser. `logout` ends every stored session |
| `project` | `list`, `show [id-or-name]`, `create <name> [--region]`, `link [id-or-name]`, `rename <name>`, `delete <id-or-name>`, `transfer <id-or-name>` | `create` and `link` write `.prisma/local.json` and gitignore it |
| `project env` | `add [KEY=VALUE\|KEY]`, `update`, `list`, `delete <key>`; scope with `--role production\|preview` or `--branch <git-name>`; `--file <dotenv>` for `add`/`update` | Values are write-only |
| `postgres` | `list`, `show`, `create <name> [--region] [--branch]`, `usage`, `delete`, `backup list\|restore`, `connection list\|create\|rotate\|delete` | Connection URLs print once |
| `bucket` | `list`, `create [--name] [--branch]`, `delete <bucket-id>`, `key list\|create\|delete` | Keys print once |
| `branch` | `list` | No create or delete |
| `git` | `connect [git-url]`, `disconnect` | `connect` needs an interactive terminal |
| `service` | `list`, `create <name> [--region] [--branch]`, `show <service>`, `open <service>`, `logs <service>`, `delete <service>` | `--project`, `--branch` on each |
| `service version` | `list <service>`, `show <id>`, `promote <id>`, `rollback <service> [--to <id>]`, `start <id>`, `stop <id>`, `delete <id>` | Version ids look like `cpv_...` |
| `service domain` | `add`, `show`, `wait [--timeout]`, `retry`, `delete`, each `<hostname> --service <service>` | Production branch only |
| `deploy <entry>` | `--name`, `--stage`, `--report <path>`, `--build-id <id>` | Composer app; does not build |
| `dev <entry>` | `--name`, `--fresh` | Composer app, local, no credentials |
| `init` | `--skills <agents>`, `--postinstall/--no-postinstall` | Local only; never edits an existing `prisma.config.ts` |
| `skills` | `sync [--disable\|--enable]`, `list` | Copies package-shipped skills |
| `feedback <message>` | `--email <address>` | Anonymous unless `--email` |
`contract`, `db`, `migration`, `orm`, `lsp`, and `telemetry` belong to Prisma ORM and the CLI itself; they are outside this skill. There is no `destroy`, `log`, `app`, `build`, `database`, `agent`, or `compute` command.
## Global Flags
Every command accepts these:
- `--json` (same as `--format json`), or `--format human|json|markdown`
- `--interactive` / `--no-interactive`
- `--yes`: accept prompt defaults; it cannot grant consent
- `--confirm <token>`: grant one consent prompt; repeat for several
- `--config <path>`: read another config file instead of `./prisma.config.ts`
- `--log-level error|warn|info|verbose`, `-v`, `-q`, `--color/--no-color`
When stdout is not a terminal the CLI already writes JSON; pass `--json` anyway so the intent is explicit. When `CI` is set (and not `false`), prompts are off.
## JSON Output
Each command prints one envelope:
```json
{"kind":"result","envelope":{"ok":false,"commandId":"","error":{"code":"CLI.UNKNOWN_COMMAND","summary":"No command registered for `app`","nextActions":[{"kind":"run-command","command":"prisma --help"}]},"nextActions":[]}}
```
On success, `envelope.ok` is `true` and `envelope.result` holds the data. On failure, branch on `envelope.error.code`; codes are a stable contract and messages are not. Codes you will meet:
| Code | Meaning |
|------|---------|
| `CLI.UNKNOWN_COMMAND` | The command does not exist in this CLI version |
| `CLI.INVALID_ARGUMENTS` | Unknown flag or bad argument |
| `CLI.CONSENT_REQUIRED` | A destructive action needs `--confirm <token>` |
| `CLI.INTERACTION_REQUIRED` | The command needs an interactive terminal (`git connect`, `auth login`) |
| `CLI.CREDENTIALS_REQUIRED` | No stored session and no `PRISMA_SERVICE_TOKEN` |
| `PROJECT.SETUP_REQUIRED` | No `--project` and no `.prisma/local.json` link |
| `SERVICE.TARGET_REQUIRED` | The service argument is missing |
| `SERVICE.NO_PREVIOUS_VERSION` | `rollback` without `--to` found nothing to roll back to |
| `CLI.CONFIG_UNREADABLE` | `prisma.config.ts` failed to evaluate (often an `effect` version conflict) |
`deploy --json` also emits step events and ends with `envelope.result.summary.nodes[].entities[]`, where each entity has `kind` (`compute-service`, `postgres-database`), `id`, and, for services, `url`.
## Targeting
- **Project:** `--project <id-or-name>`, else the `.prisma/local.json` link, else `PROJECT.SETUP_REQUIRED`. Only `project create` and `project link` write the link; `deploy` does not.
- **Branch:** `--branch <git-name>`. Without it, commands target the project's default branch, which is production. The current Git branch is not consulted.
- **Service:** the first positional argument. There is no picker and no environment fallback.
- **Version:** version ids are globally unique, so `service version show|promote|start|stop|delete <id>` need no other scope.
Environment variables the CLI reads for the Platform: `PRISMA_SERVICE_TOKEN` (overrides stored sessions; a set-but-empty value is an error), `PRISMA_WORKSPACE_ID` (the workspace for a service token), `PRISMA_REGION` (region for a project the first deploy creates), and `PRISMA_COMPOSER_REPORT_FILE` (same as `--report`). `PRISMA_SKILLS_CHECK=0` silences the out-of-date skills notice. It does not read `PRISMA_PROJECT_ID`, `PRISMA_APP_ID`, or `PRISMA_SERVICE_ID`.
## Consent Tokens
These commands stop at a consent prompt. In a non-interactive run, pass the token with `--confirm`; `--yes` fails with `CLI.CONSENT_REQUIRED`.
| Command | Token |
|---------|-------|
| `project delete <project>` | Project id |
| `project transfer <project>` | Project id |
| `postgres delete <database>` | Database id |
| `postgres backup restore <database> --backup <id>` | Target database id |
| `postgres connection rotate <connection-id>` | Connection id |
| `postgres connection delete <connection-id>` | Connection id |
| `bucket delete <bucket-id>` | Bucket id |
| `service delete <service>` | Service name |
| `service version delete <version-id>` | Version id |
| `service version rollback <service> --to <version-id>` | Target version id |
| `service domain delete <hostname>` | Hostname |
```bash
npx prisma service version rollback api --project my-app --to cpv_123 --confirm cpv_123 --json
```
Run a consent-gated command only when the user asked for that specific action.
## Bad
```bash
bunx @prisma/cli@latest app deploy --prod --yes --env .env
npx prisma service delete api --yes
```
`app deploy` fails with `CLI.UNKNOWN_COMMAND`, and `--yes` cannot answer the consent prompt for `service delete`.
## Good
```bash
npm run build
npx prisma deploy module.ts --stage feat-search --json
npx prisma service delete api --branch feat-search --confirm api --json
```
## References
- [CLI reference](https://www.prisma.io/docs/cli)
- [Global flags](https://www.prisma.io/docs/cli/global-flags)
- [Error reference](https://www.prisma.io/docs/cli/error-reference)
@@ -0,0 +1,121 @@
# debug-deploy-failures
Diagnose Compute failures from the error code first, then the symptom.
## Priority
HIGH
## Why It Matters
Most failures carry a structured code and a `nextActions` list that names the fix. Guessing from the message, or retrying commands from the removed CLI, wastes the user's time and can deploy into the wrong place.
## First Checks
```bash
npx prisma --version
npx prisma auth whoami --json
npx prisma project show --json
ls module.ts prisma.config.ts
node --version
test -f .env && sed 's/=.*/=<redacted>/' .env
```
Re-run the failing command with `--json` (and `--report deploy-report.json` for `deploy`) and read `error.code`, `error.why`, and `nextActions`. Never print token or connection-string values.
## CLI and Setup
| Symptom | Cause | Fix |
|---------|-------|-----|
| `CLI.UNKNOWN_COMMAND` for `app`, `build`, `database`, `agent`, `destroy`, `compute` | The command was removed | Use the replacement in the SKILL.md table |
| `Unknown command "auth"` or `"deploy"`, or `prisma dev` starts a database server | A Prisma 6 or 7 `prisma` binary | Install `prisma` 8.x as a dev dependency, or use `npx @prisma/cli@latest` |
| `ERR_UNKNOWN_FILE_EXTENSION` | Node.js too old to load `module.ts`. Composer supports 22.18 or newer on the 22 line, 24.11 or newer on the 24 line, or 26 or newer | Upgrade Node.js |
| `CLI.CONFIG_UNREADABLE` with a module error from `effect` | Another `effect` version hoisted over the one `@prisma/composer` pins | Match the app's `effect` to `@prisma/composer`'s `dependencies.effect`, or force it with `overrides` (npm), `pnpm.overrides` or `pnpm-workspace.yaml` `overrides` (pnpm), `resolutions` (Yarn); reinstall |
| `CLI.CONFIG_SECTION_INVALID` with `CONFIG.SECTION_MISSING` | No `composer` section in `prisma.config.ts` | Add the section ([`app-composer-setup.md`](app-composer-setup.md)) |
| `CONFIG.FILE_RETIRED` or `CONFIG.FIELD_RETIRED` | A `prisma-composer.config.ts` or `configPath` from an older Composer | Move `extensions` and `state` into the `composer` section and delete the old file |
| `ASSEMBLE.EXTENSION_MISSING` | A service uses `nextjs()` but `nextjsBuild()` is not in `extensions` | Add `nextjsBuild()` from `@prisma/composer/nextjs/control` |
| `COMPOSE.GRAPH_INVALID` naming an id | A provision id or service name with a hyphen or other non-alphanumeric character | Use `[A-Za-z0-9]` only; at least three characters for provision ids |
| Bun APIs fail while the CLI loads `module.ts` | The `prisma` bin runs under Node | `bun node_modules/.bin/prisma deploy module.ts` |
## Auth and Project
| Symptom | Cause | Fix |
|---------|-------|-----|
| `CLI.CREDENTIALS_REQUIRED` | No session and no service token | Ask the user to run `npx prisma auth login`; in CI set `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` |
| Error about a blank `PRISMA_SERVICE_TOKEN` | The variable is set but empty | Unset it or provide a token |
| Commands act in the wrong workspace | Another stored session is current, or a service token overrides it | `auth workspace list --json`, then `auth workspace use <id>`; unset `PRISMA_SERVICE_TOKEN` to use sessions |
| `PROJECT.SETUP_REQUIRED` after a successful deploy | `deploy` does not link the directory | `npx prisma project link <app-name>` or pass `--project` |
| `project "<name>" does not exist yet and no deploy region is configured` | First deploy without a region | `prismaCloud({ region })` or `PRISMA_REGION` |
| Deploy refuses an existing project name (`HostedStateBootstrapError`, or `a project with this name already exists`) | A project with the module's name exists that this module did not create | `deploy --name <unique-name>`, or rename the module |
| Deploy fails immediately naming another holder | Another deploy of the same environment holds the state lease | Wait for it; a crashed deploy's lease expires after about a minute |
## Deploy Pipeline
| Symptom | Cause | Fix |
|---------|-------|-----|
| `ASSEMBLE.BUILD_FAILED` | The built entry or directory is missing or invalid (no build, wrong path, symlinks in a `dir` build) | Run the build and check that `entry`/`dir` match its output, relative to `service.ts` |
| `ASSEMBLE.SERVICE_MISSING` | The module provisions no service | Provision at least one `compute()` service |
| `DEPLOY.STAGE_INVALID` | The stage is not a valid Git ref name | Rename the stage |
| A connection input "declares param ..., but its producer ... did not supply it" | An authored connection or extension does not supply a declared value | Fix the producer's outputs; mark the param optional only if absent is valid |
| Deploy fails early naming a missing variable | An `envParam`/`envSecret` name is unset on the stage and in the shell | Export it in the deploying shell or set it with `project env add` |
| `MIGRATION_PATH_NOT_FOUND` | A `postgres(contract)` schema change has no committed migration | `prisma contract emit`, `prisma migration plan --name <slug>`, commit `migrations/` |
| `DEPLOY.ENGINE_FAILED` | The deploy engine or the platform rejected the generated stack | Read the engine lines in the error; it names `.prisma-composer/alchemy.run.ts` and a command that reproduces the failure |
| `DEPLOY.BUILD_REQUIRED` from `destroy` | `destroy` packages the built app too | Build, then destroy |
## Deployed but Not Working
| Symptom | Cause | Fix |
|---------|-------|-----|
| Public URL times out or returns 502 at once | Listener on `localhost`, wrong port, or a crash at boot | Bind `0.0.0.0` on `service.port()`; read `npx prisma service logs <service>` |
| `Cannot find package`, `Cannot find module`, or `ENOENT while resolving package` in logs | The build left a package as an import, and the default `dependencies: "bundled"` ships only the build output | Bundle every dependency (`bun build --target=bun`), or set `dependencies: "external"` on `node()` so the deploy stages the installed packages |
| 502s in a loop after the app was idle | A database client dies when idle connections close | Small reconnect-friendly pool; log `uncaughtException` and `unhandledRejection` instead of exiting |
| `504 Gateway Time-out` with an `openresty` body after about 60 seconds | The handler sent nothing for 60 seconds | Respond first, continue under `waitUntil`, or queue the work |
| Background work stops or never finishes | The instance slept | `waitUntil` or `KeepAwakeGuard` from `@prisma/compute`; persist progress |
| `401` from a deployed `/rpc/<method>` | Composer's service-key check; only wired consumers may call | Test through a consumer or locally; not a deploy failure |
| `RUNTIME.TEMPORAL_UNAVAILABLE` or a failure on the first timestamp read | No global `Temporal` on the runtime | Import a Temporal polyfill at the server entry, or use string column types |
| Next.js page shows build-time or missing values from `service.load()` | The route was prerendered | `export const dynamic = "force-dynamic"` |
| `ECONNRESET` calling another service | The callee was cold-starting | Retry |
| A changed env var has no effect | Values resolve at deploy time | Redeploy (or promote) |
| A resource disappeared after a deploy | Its `provision()` was removed from `module.ts` | Restore the declaration and redeploy |
| A preview's database is empty | Stages get their own empty databases | Seed it; production data is never copied |
## Deploy on Push
| Symptom | Cause | Fix |
|---------|-------|-----|
| Push builds nothing, no error | No workflow on the pushed branch | Add `.github/workflows/prisma-deploy.yml` ([`deploy-on-push.md`](deploy-on-push.md)) |
| Green run with `skipped-no-credential` | Repository not connected, no `id-token: write`, or a fork | `npx prisma git connect`, add the permission |
| `CLI.UNKNOWN_COMMAND` inside the action | Action release v1.5.0 or older | Use `prisma/cloud-deploy-action@v1` (v1.9.0 or later) |
| Install step fails on pnpm or Yarn | The action auto-detects npm and Bun only | Set `install-command` |
## Custom Domains
`npx prisma service domain show <hostname> --service <service> --json` prints the state and the DNS record it expects. `SERVICE.DOMAIN_DNS_NOT_CONFIGURED` means the CNAME is not visible yet; create it, then run `add` again. After fixing DNS on a `failed` domain, run `service domain retry`. `SERVICE.BRANCH_NOT_DEPLOYABLE` means a preview branch was targeted; domains are production only.
## Local Development
- `dev` lists services from other apps: the emulators are shared machine-wide daemons. Ignore names not in your `module.ts`.
- `dev --fresh` fails for an app with a database in this release. Follow the reset steps in [Local development](https://www.prisma.io/docs/composer/local-development#whats-local-vs-whats-real).
- Windows is not supported for the local stack.
## Report CLI Bugs
When a failure survives these checks or the CLI reports an internal error, send it to the CLI team without secrets:
```bash
npx prisma feedback "deploy failed with DEPLOY.UNEXPECTED: <first error line>"
```
## Bad
Retrying `bunx @prisma/cli@latest app deploy --prod --yes` after `CLI.UNKNOWN_COMMAND`, or editing code before reading `error.code`.
## Good
Re-run with `--json --report deploy-report.json`, read `error.code` or `failure.code`, apply the fix this table names, rebuild, and deploy again.
## References
- [Deploying](https://www.prisma.io/docs/composer/deploying)
- [Request timeout](https://www.prisma.io/docs/compute/request-timeout)
- [CLI error reference](https://www.prisma.io/docs/cli/error-reference)
@@ -0,0 +1,138 @@
# deploy-cli-and-ci
Deploy a Composer app with `prisma deploy`: production or a stage, from a workstation or from CI.
## Priority
HIGH
## Why It Matters
`deploy` does not build, chooses the project by the app's name rather than the directory link, and targets production unless told otherwise. Getting any of these wrong ships stale code, deploys into the wrong project, or changes production by accident.
## Commands
```bash
npx prisma deploy module.ts --help
npx prisma dev module.ts --help
```
| You want to | Run |
|-------------|-----|
| Run the app locally, no credentials | `npm run build && npx prisma dev module.ts` |
| Deploy a preview | `npm run build && npx prisma deploy module.ts --stage <name>` |
| Deploy production | `npm run build && npx prisma deploy module.ts` |
| Deploy under another app name | `npx prisma deploy module.ts --name <name>` |
| Write the outcome as JSON | `npx prisma deploy module.ts --report deploy-report.json` |
`<entry>` is the file whose default export is the root module, usually `module.ts`.
## Before Deploying
1. Build. `deploy` and `dev` package what the build already produced.
2. Run `npx prisma dev module.ts` and request each local URL it prints. It runs the same pipeline against local emulators, with a real local Postgres, and needs no account. `Ctrl-C` leaves local data in place.
3. Check auth: `npx prisma auth whoami --json`. If no one is signed in, ask the user to run `npx prisma auth login`; it opens a browser and cannot be done by an agent.
4. For a new project, set a region: `prismaCloud({ region })` in `prisma.config.ts` or `PRISMA_REGION`.
5. Decide the target with the user. No `--stage` changes production.
## Production and Stages
- No `--stage`: production. In platform terms the app is a project named after the root module, and production is its default branch.
- `--stage <name>`: a complete, isolated copy of the app as a preview branch of the same project, with its own services, databases, and configuration. Only the code is shared. The name must be a valid Git ref name; an invalid one fails the deploy.
- Redeploying is idempotent: the deploy compares the module with the recorded deploy state and applies the difference. Removing a `provision()` from the module deletes that resource on the next deploy. A deploy never deletes the last service, the project, or a branch.
- Deploy state lives on the platform, per branch, so a workstation and CI see the same state. Concurrent deploys of one environment take turns through a lease; a second deploy fails while the first holds it, and a crashed deploy's lease expires after about a minute.
## Which Project
The deploy finds the project in the workspace by the root module name (or `--name`) and creates it if none exists. It does not read or write `.prisma/local.json`, and it has no `--project` flag.
- A project with the same name that this module did not create can stop the deploy. Deploy with `--name <unique-name>` or rename the module.
- After the first deploy, link the directory so other commands target the project: `npx prisma project link <app-name>`. Otherwise pass `--project <app-name>` to `service`, `git`, and `project env` commands.
## Credentials
| Where | How |
|-------|-----|
| Workstation | `npx prisma auth login` once; later commands, including an agent's, reuse the stored session |
| CI or headless | `PRISMA_SERVICE_TOKEN` (a workspace service token from Console settings) and `PRISMA_WORKSPACE_ID` |
| GitHub Actions on a connected repository | OIDC through `prisma/cloud-deploy-action`; no stored secret. See [`deploy-on-push.md`](deploy-on-push.md) |
A non-empty `PRISMA_SERVICE_TOKEN` takes priority over stored sessions. A set-but-empty value is an error. Never print the token; check presence with `test -n "${PRISMA_SERVICE_TOKEN:-}"`.
Input fields bound with `envParam`/`envSecret` are stored per stage. A fresh stage starts with none, so CI must export those values; the first deploy copies missing names from the shell to the stage.
## Output
A deploy prints each step and ends with the app tree: every authored name, the platform resource it became, and public URLs.
```text
my-app
├─ db postgres-database db_def456
└─ api compute-service cps_abc123
https://xyz.ewr.prisma.build
```
With `--json`, the final envelope's `result.summary.nodes[].entities[]` lists what was deployed, each with `kind`, `id`, and `url` for services. `--report <path>` (or `PRISMA_COMPOSER_REPORT_FILE`) writes the outcome as JSON, including `failure.code` when the deploy fails. Request each service URL after the deploy:
```bash
curl -i https://xyz.ewr.prisma.build
```
## CI Without GitHub
Any CI runs the same commands with the two credential variables as secrets:
```bash
npm ci
npm run build
npx prisma deploy module.ts --stage "pr-$PR_NUMBER" --json --report deploy-report.json
```
`--build-id <id>` joins a build record your CI already created through `POST /v1/builds`.
## Teardown
The CLI has no `destroy` command, and `branch` has no delete.
- Connected GitHub repository: deleting the Git branch tears down the matching preview (services, databases, buckets). Production and the default branch are never torn down this way.
- Otherwise: call `destroy` from `@prisma/composer/control` with an explicit target. It needs `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` in the environment and the app already built:
```ts
// destroy-stage.ts
import { destroy } from "@prisma/composer/control";
import prismaConfig from "./prisma.config.ts";
const result = await destroy({
entry: "module.ts",
config: { value: prismaConfig.composer, file: "prisma.config.ts" },
target: { kind: "stage", stage: "pr-42" },
});
if (!result.ok) throw new Error(`${result.failure.code}: ${result.failure.message}`);
```
`config` is required in `@prisma/composer` 0.28.0: the `composer` section and the path of the file that declares it. Pass `name` when the app was deployed with `--name`. `target` is `{ kind: "stage", stage }` or `{ kind: "production" }` and has no default. Destroying a stage removes its resources, branch, and data; destroying production removes its resources and deletes the project once it is empty. Get the user's confirmation first. The deploy action's `mode: destroy` does not work against the current CLI.
## Bad
```bash
npx prisma deploy module.ts
```
Run without a build, this deploys whatever stale output is on disk, and without `--stage` it targets production.
## Good
```bash
npm run build
npx prisma dev module.ts # verify locally, then Ctrl-C
npx prisma auth whoami --json
npx prisma deploy module.ts --stage feat-search --json --report deploy-report.json
npx prisma project link my-app
npx prisma service list --branch feat-search --json
```
## References
- [`deploy` command](https://www.prisma.io/docs/cli/deploy)
- [Deploying](https://www.prisma.io/docs/composer/deploying)
- [Local development](https://www.prisma.io/docs/composer/local-development)
@@ -0,0 +1,101 @@
# deploy-on-push
Deploy every pushed branch from the repository's own GitHub Actions with `prisma/cloud-deploy-action`.
## Priority
HIGH
## Why It Matters
The platform does not build on push. A connected repository without a workflow deploys nothing and reports no error, and a workflow without the connection skips with a green run. Both pieces are required, and a push to the default branch deploys production without any further prompt.
## How It Works
1. **The connection.** `prisma git connect` installs the Prisma GitHub App (if needed) and links the repository to the project. It lets workflow runs exchange their GitHub OIDC token for a 30-minute workspace token, and it tears down a preview when its Git branch is deleted.
2. **The workflow.** `prisma/cloud-deploy-action` runs install, your build command, and `prisma deploy <module>`. The default branch deploys production; any other branch deploys a stage named after it.
The Console can do both at once: importing the repository there opens a pull request that adds the workflow. The CLI only creates the connection.
## Setup From the CLI
```bash
npx prisma project link <app-name> # deploy does not link the directory
npx prisma git connect # uses the origin remote; needs an interactive terminal
```
`git connect` opens a browser for the GitHub App install and waits, so a person has to run it. With `--no-interactive` it fails with `CLI.INTERACTION_REQUIRED`; use the Console instead in that case. It fails with `PROJECT.SETUP_REQUIRED` when the directory is not linked.
Then commit the workflow:
```yaml
# .github/workflows/prisma-deploy.yml
name: prisma-deploy
on:
push:
concurrency:
group: prisma-deploy-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
id-token: write
jobs:
deploy:
if: github.ref_type == 'branch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- uses: oven-sh/setup-bun@v2
- uses: prisma/cloud-deploy-action@v1
with:
build-command: npm run build
```
- `id-token: write` is required for the OIDC exchange.
- Bun 1.3.10 or newer must be on the runner `PATH`; `oven-sh/setup-bun@v2` provides it.
- GitHub reads the workflow from the pushed commit, so a branch created before the file existed deploys nothing until it contains the file.
## Action Inputs and Outputs
Inputs (from `action.yml` in v1.9.0):
| Input | Default | Notes |
|-------|---------|-------|
| `build-command` | `npm run build` | Run verbatim; `none` skips the build |
| `install-command` | auto | `npm ci` or `bun install --frozen-lockfile` from the lockfile; pnpm and yarn need an explicit value |
| `module` | `module.ts` | The Composer entry |
| `stage` | derived | Empty: default branch is production, other branches become a stage of the same name |
| `working-directory` | `.` | For monorepos |
| `prisma-version` | `8.0.0-rc.9` | Used only when the repository has no `prisma` dev dependency; otherwise the installed version deploys |
| `mode` | `deploy` | `destroy` does not work against the current CLI |
Outputs: `outcome` (`succeeded`, `failed`, `skipped-no-credential`), `url` (root service), `urls` (JSON map of service address to URL), `build-id`, `report-path`. Repositories that are not connected can pass `PRISMA_SERVICE_TOKEN` from a secret in the step's `env`; an explicit token wins over OIDC.
## Checking a Push
- Watch the run in the repository's Actions tab. The job summary lists each service URL and, on failure, the cause.
- `outcome: skipped-no-credential` means the repository is not connected, `id-token: write` is missing, or the run came from a fork.
- `CLI.UNKNOWN_COMMAND` in the deploy step means an action release up to v1.5.0, which called the removed `prisma composer` commands. Use `@v1` (v1.9.0 or later).
- From a terminal: `npx prisma service list --branch <git-branch> --json`.
- Deleting the Git branch removes the preview's services, databases, and buckets. Production and the default branch are never torn down.
## Bad
Running `npx prisma git connect`, pushing, and reporting the app as deployed. The connection alone builds and deploys nothing.
## Good
Connect, commit `.github/workflows/prisma-deploy.yml`, push a non-default branch first, confirm the run's `url` responds, and only then merge to the default branch with the user's go-ahead.
## References
- [Deploy on push](https://www.prisma.io/docs/compute/deploy-on-push)
- [GitHub integration](https://www.prisma.io/docs/compute/github)
- [prisma/cloud-deploy-action](https://github.com/prisma/cloud-deploy-action)
@@ -0,0 +1,148 @@
# ops-services-and-config
Inspect and operate what a deploy created: services, versions, logs, domains, environment variables, databases, and buckets.
## Priority
HIGH
## Why It Matters
Operations commands target explicitly: the service is a positional argument, the project comes from `--project` or the directory link, and the branch defaults to production. An agent that relies on the old `app` commands, on `PRISMA_SERVICE_ID`, or on the current Git branch reads or changes the wrong thing.
Every example below accepts `--project <id-or-name>` and `--json`. Without `--branch`, commands act on the production branch.
## Services
A service is one HTTP app on a branch. Every deploy creates an immutable version; one version serves traffic at a time.
```bash
npx prisma service list --json
npx prisma service list --branch feat-search --json
npx prisma service show api --json
npx prisma service open api
```
`service show` returns the live version and the service URL. `service create` exists but is rarely needed; deploys create services.
## Logs
```bash
npx prisma service logs api --tail 200
npx prisma service logs api --follow
npx prisma service logs api --branch feat-search
npx prisma service logs api --version-id cpv_123 --from-start
```
Logs default to the live version. Use `--version-id` for a failed or stopped version. `SERVICE.LOGS_FAILED` carries the API status; `SERVICE.LOGS_INCOMPLETE` means the page ended early, so rerun. Build output is not here: read the GitHub Actions run, the terminal that ran `deploy`, the `--report` file, or the Console.
## Versions, Promote, Rollback
```bash
npx prisma service version list api --json
npx prisma service version show cpv_123 --json
npx prisma service version promote cpv_123
npx prisma service version rollback api --to cpv_122 --confirm cpv_122
npx prisma service version stop cpv_123
npx prisma service version start cpv_123
npx prisma service version delete cpv_123 --confirm cpv_123
```
- `promote` takes a version from a preview branch to production by rebuilding it with production env vars.
- `rollback` puts production back on an existing version without a rebuild. Without `--to` it picks the version before the live one (`SERVICE.NO_PREVIOUS_VERSION` or `SERVICE.LIVE_VERSION_UNKNOWN` when it cannot), and it asks for consent with the target version id. In a non-interactive run, list versions first and pass `--to <id> --confirm <id>`.
- A later production deploy creates a new version and makes it live, so fix the code before the next deploy after a rollback.
## Custom Domains
Domains attach to a service's production branch only, CNAME-based, up to three per service.
```bash
npx prisma service domain add shop.example.com --service web
npx prisma service domain wait shop.example.com --service web --timeout 15m
npx prisma service domain show shop.example.com --service web --json
npx prisma service domain retry shop.example.com --service web
npx prisma service domain delete shop.example.com --service web --confirm shop.example.com
```
`add` verifies DNS first. If the CNAME is not visible yet, it fails with the record to create (pointing at `switchboard.<region>.prisma.build`); create it and run `add` again. `wait --timeout 0` does one status check. States: `pending_dns`, `provisioning_tls`, `active`, `failed`.
## Environment Variables
Three layers: production values, preview values shared by every preview branch, and per-branch overrides on top of preview. Production values cannot be branch-scoped.
```bash
npx prisma project env list --json
npx prisma project env list --role preview --json
npx prisma project env list --branch feat-search --json
npx prisma project env add STRIPE_KEY --role production # value read from the shell environment
npx prisma project env add --file .env.preview --role preview
npx prisma project env add API_BASE_URL=https://staging.example.com --branch staging
npx prisma project env update STRIPE_KEY --role production
npx prisma project env delete STRIPE_KEY --role preview
```
- Every write names its scope: `--role production`, `--role preview`, or `--branch <name>`.
- `add` fails when the key exists in that scope; use `update`.
- Values are write-only. `list` shows names and metadata, never values, and nothing pulls them back into a `.env`.
- Values resolve at deploy time. A change applies on the next deploy (or `promote`).
- Keys match `[A-Z_][A-Z0-9_]*`; values are non-empty, up to 8 KB.
- Passing only `KEY` reads the value from the current environment and keeps it out of shell history.
- `COMPOSER_*` variables belong to the deploy and are rewritten on every deploy. Do not edit them.
## Databases and Buckets
A Composer app gets its databases and buckets from its module. These commands inspect them or create standalone ones.
```bash
npx prisma postgres list --json
npx prisma postgres list --branch feat-search --json
npx prisma postgres show db_123 --json
npx prisma postgres usage db_123 --json
npx prisma postgres connection create db_123 --name ci
npx prisma postgres connection rotate conn_123 --confirm conn_123
npx prisma postgres backup list db_123 --json
npx prisma bucket list --json
npx prisma bucket key create bkt_123 --role read
```
`postgres create`, `postgres connection create`, `postgres connection rotate`, and `bucket key create` print credentials exactly once. Store them in the intended secret store immediately and never echo them back. Deleting a database, restoring a backup, or deleting a bucket destroys data; do it only when the user asks, with the exact id as `--confirm`.
## Branches
```bash
npx prisma branch list --json
```
`branch` only lists. Branches are created by a stage deploy, a pushed Git branch, or `service create --branch`, and removed by deleting the Git branch of a connected repository or by the control API's `destroy`.
## Workspaces
```bash
npx prisma auth whoami --json
npx prisma auth workspace list --json
npx prisma auth workspace use <workspace-id>
npx prisma auth workspace logout <workspace-id>
```
`auth login` adds a session per workspace; `workspace use` switches. While `PRISMA_SERVICE_TOKEN` is set it overrides every stored session. `auth logout` ends all sessions.
## Bad
```bash
npx prisma service logs
```
Fails with `SERVICE.TARGET_REQUIRED`; there is no picker and no `PRISMA_SERVICE_ID` fallback.
## Good
```bash
npx prisma service logs api --project my-app --branch feat-search --tail 200 --json
```
## References
- [Deployments](https://www.prisma.io/docs/compute/deployments)
- [Environment variables](https://www.prisma.io/docs/compute/environment-variables)
- [Domains](https://www.prisma.io/docs/compute/domains)
- [`service` command](https://www.prisma.io/docs/cli/service)
@@ -0,0 +1,101 @@
# runtime-requirements
What a service must do to run on Prisma Compute, and the platform limits it must design around.
## Priority
CRITICAL
## Why It Matters
A deploy can converge cleanly and still serve nothing: a loopback listener is unreachable, a slow handler gets a `504` from the ingress, and a sleeping instance stops background work. None of these show up as deploy errors.
## Runtime
- Services run on **Bun**, in a VM next to their Prisma Postgres database. Write server code for Bun, and bundle with `bun build --target=bun` or another bundler that inlines all dependencies. A build that leaves packages as imports needs `dependencies: "external"` on `node()` (Composer 0.29.0 and later).
- There is no global `Temporal`. A service that reads Prisma ORM `DateTime` columns as `Temporal` values compiles, deploys, then fails on the first read. Import a polyfill at the server entry or use string column types.
## Host and Port
- Listen on `service.port()` (default 3000). The runtime also exports it as `PORT`.
- Bind `0.0.0.0`. Compute routes external HTTP to the VM; a `localhost` or `127.0.0.1` listener looks started but is unreachable.
```ts
Bun.serve({ port: service.port(), hostname: "0.0.0.0", fetch: handler });
```
## 60 Seconds to First Byte
The ingress gives a request 60 seconds to start responding. If nothing comes back, the client gets `504 Gateway Time-out` (a short `openresty` HTML body) and Compute cancels the request. Your handler sees only its abort signal (`req.signal`); no error is logged.
- Respond within 60 seconds. For webhooks, return `200` or `202` before processing.
- Keep in-request timeouts (fetch timeouts, `AbortSignal.timeout`) under 60 seconds so your own error handling runs first.
- Continue longer work after the response with `waitUntil`, or persist a job and process it in steps from a separate trigger. Compute does not run scheduled jobs; the trigger is an external scheduler or the Composer `cron` module.
- The deadline covers only the first bytes. The docs say a response that has started is not cut off; the `prisma-composer-core-concepts` skill warns that the ingress buffers streamed responses. Send the first bytes early and test a streaming route on a stage before relying on it.
## Sleep and Keep-Awake
Idle instances scale to zero: the platform snapshots memory and resumes from it on the next request. Requests are unaffected, but `setTimeout`, `setInterval`, and floating promises can stall mid-flight. Do not build schedulers on `setInterval` inside a service.
`@prisma/compute` keeps an instance awake on a best-effort basis:
```ts
import { KeepAwakeGuard, waitUntil } from "@prisma/compute";
waitUntil(processJob(job), { signal: AbortSignal.timeout(10 * 60_000) });
async function processBatch() {
using guard = new KeepAwakeGuard({ signal: AbortSignal.timeout(30_000) });
await doWork();
}
```
- The `signal` caps how long the instance stays awake; it does not cancel the work.
- Release a manually created guard in `finally` with `guard.release()` where `using` is unavailable.
- Neither primitive makes work durable, retries it, or carries it through a restart or a new deployment.
## Connections
Scale to zero closes idle database connections. A long-lived client that treats a dropped connection as fatal crash-loops through `502`s. Keep pools small and reconnect-friendly, and log instead of exiting:
```ts
const sql = new SQL({ url: db.url, max: 1, idleTimeout: 10 });
process.on("uncaughtException", (err) => console.error("uncaughtException", err));
process.on("unhandledRejection", (err) => console.error("unhandledRejection", err));
```
A call into a sleeping service can get `ECONNRESET` during the cold start; retry it. The generated Composer RPC client already does.
## Limits
- No WebSocket servers.
- No persistent filesystem.
- No multi-region deployments. Each service runs in one region, and a Composer deploy uses the project's region, fixed when the first deploy creates the project: `us-east-1`, `us-west-1`, `eu-west-3`, `eu-central-1`, `ap-northeast-1`, or `ap-southeast-1`.
- A deployed `/rpc/<method>` of a Composer contract returns `401` to anything except the services wired to it. That is the service-key check, not a broken deploy.
## Bad
```ts
app.post("/webhook", async (c) => {
await processForTwoMinutes(await c.req.json());
return c.text("done");
});
```
The caller gets a `504` after 60 seconds, and the instance can sleep while the work continues.
## Good
```ts
app.post("/webhook", async (c) => {
const job = await c.req.json();
waitUntil(processForTwoMinutes(job), { signal: AbortSignal.timeout(5 * 60_000) });
return c.body(null, 202);
});
```
## References
- [Request timeout](https://www.prisma.io/docs/compute/request-timeout)
- [Keeping instances awake](https://www.prisma.io/docs/compute/keeping-instances-awake)
- [Known limitations](https://www.prisma.io/docs/compute/limitations)
@@ -0,0 +1,14 @@
---
name: prisma-database-setup
description: Deprecated compatibility name for prisma-orm-setup. Use only when a user or existing integration explicitly invokes prisma-database-setup; otherwise select prisma-orm-setup.
license: MIT
metadata:
author: prisma
version: "8.0.0"
---
# Deprecated: prisma-database-setup
Load `prisma-orm-setup` with the host's skill loader or read its installed `SKILL.md`. If unavailable, install it from [prisma/skills](https://github.com/prisma/skills/tree/main/prisma-orm-setup) before continuing. It covers Prisma 6, 7, and 8 setup and connection repair.
This compatibility entry contains no setup recipes. Keep it until consumers have migrated to the replacement.
@@ -0,0 +1,270 @@
---
name: prisma-driver-adapter-implementation
description: Required reference for Prisma ORM 7 SQL driver adapter work. Use when implementing or modifying adapters, adding database drivers, or touching SqlDriverAdapter, Transaction, savepoint, result mapping, or DriverAdapterError behavior. Covers current transaction lifecycle, optional savepoint hooks, original database-error preservation, and verification.
license: MIT
metadata:
author: prisma
version: "7.9.1"
---
# Prisma SQL Driver Adapter Implementation
Use this guide with the exact `@prisma/driver-adapter-utils` version installed by the target Prisma release. Driver adapters are a protocol boundary: type-compatible code can still corrupt values, leak connections, or break transactions.
## When to Apply
- Implementing `SqlDriverAdapterFactory`, `SqlMigrationAwareDriverAdapterFactory`, `SqlDriverAdapter`, or `Transaction`
- Adding nested-transaction/savepoint support
- Mapping driver values, column metadata, bind arguments, or database errors
- Debugging `P2039`, transaction leaks, shadow-database failures, or adapter-specific query behavior
## Contract snapshot
```typescript
interface SqlDriverAdapterFactory extends AdapterInfo {
connect(): Promise<SqlDriverAdapter>
}
interface SqlMigrationAwareDriverAdapterFactory extends SqlDriverAdapterFactory {
connectToShadowDb(): Promise<SqlDriverAdapter>
}
interface SqlDriverAdapter extends AdapterInfo {
queryRaw(query: SqlQuery): Promise<SqlResultSet>
executeRaw(query: SqlQuery): Promise<number>
executeScript(script: string): Promise<void>
startTransaction(isolationLevel?: IsolationLevel): Promise<Transaction>
getConnectionInfo?(): ConnectionInfo
dispose(): Promise<void>
}
interface Transaction extends AdapterInfo {
readonly options: { usePhantomQuery: boolean }
queryRaw(query: SqlQuery): Promise<SqlResultSet>
executeRaw(query: SqlQuery): Promise<number>
commit(): Promise<void>
rollback(): Promise<void>
createSavepoint?(name: string): Promise<void>
rollbackToSavepoint?(name: string): Promise<void>
releaseSavepoint?(name: string): Promise<void>
}
```
`IsolationLevel` currently includes `READ UNCOMMITTED`, `READ COMMITTED`, `REPEATABLE READ`, `SNAPSHOT`, and `SERIALIZABLE`; validate what the concrete database supports.
## Priority rules
| Priority | Rule | Impact |
|----------|------|--------|
| CRITICAL | One dedicated connection per transaction | Prevents interleaving and leaks |
| CRITICAL | `commit`/`rollback` are lifecycle cleanup hooks | Prevents duplicate COMMIT/ROLLBACK |
| CRITICAL | Savepoints live on `Transaction`, not adapter-global depth | Makes nested scopes connection-local |
| CRITICAL | Preserve original database error code/message | Enables useful `P2039` fallback |
| HIGH | Map arguments and result metadata exactly | Prevents silent value corruption |
| HIGH | Shadow databases are isolated and always cleaned up | Makes Migrate safe |
| HIGH | Dispose only resources the adapter owns | Prevents shutting down caller-owned pools |
## Query implementation
`SqlQuery` contains `sql`, `args`, and parallel `argTypes`. Map each argument using both value and `ArgType`; do not discard type/arity information. Execute in the driver's array/tuple row mode so column order is stable.
```typescript
class ExampleQueryable {
readonly provider = 'postgres' as const
readonly adapterName = '@acme/adapter-example'
constructor(protected readonly connection: DriverConnection) {}
async queryRaw(query: SqlQuery): Promise<SqlResultSet> {
try {
const result = await this.connection.query({
text: query.sql,
values: query.args.map((value, index) =>
mapArg(value, query.argTypes[index]),
),
rowMode: 'array',
})
return {
columnNames: result.fields.map((field) => field.name),
columnTypes: result.fields.map(mapColumnType),
rows: result.rows,
}
} catch (error) {
throwAdapterError(error)
}
}
async executeRaw(query: SqlQuery): Promise<number> {
try {
const result = await this.connection.execute(
query.sql,
query.args.map((value, index) => mapArg(value, query.argTypes[index])),
)
return result.rowsAffected ?? 0
} catch (error) {
throwAdapterError(error)
}
}
}
```
### Result mapping
Return `columnNames`, `columnTypes`, and `rows` with identical lengths/order. Map driver metadata to `ColumnTypeEnum` deliberately:
- signed integer widths to `Int32`/`Int64`; preserve 64-bit values without JS number truncation
- decimal/numeric to `Numeric` using the representation expected by Prisma
- binary to `Uint8Array`/`Bytes`
- date-only, time-only, and timestamp to `Date`, `Time`, and `DateTime`
- UUID, JSON, enum, arrays, and provider-specific unknown values to their explicit types
- unsupported native types to `DriverAdapterError({ kind: 'UnsupportedNativeDataType', type })`
Test `null`, empty arrays, array element types, big integers, decimals, byte arrays, JSON, dates, and user-defined/unknown native types.
### Script execution
`executeScript` must execute a migration script as the provider expects. Prefer the driver's native multi-statement/script facility or a real SQL parser. Naively splitting on `;` breaks functions, triggers, quoted strings, and dialect-specific blocks.
## Transaction protocol
`startTransaction` must acquire one dedicated connection, start the database transaction, apply the requested isolation level, and return a `Transaction` bound to that same connection. If setup fails, release it immediately.
```typescript
async startTransaction(level?: IsolationLevel): Promise<Transaction> {
const connection = await this.pool.acquire()
try {
const tx = new ExampleTransaction(connection, () => connection.release())
await tx.executeRaw({ sql: 'BEGIN', args: [], argTypes: [] })
if (level) {
await tx.executeRaw({
sql: `SET TRANSACTION ISOLATION LEVEL ${validateLevel(level)}`,
args: [],
argTypes: [],
})
}
return tx
} catch (error) {
connection.release(error)
throwAdapterError(error)
}
}
```
### Commit and rollback
Prisma coordinates the SQL `COMMIT`/`ROLLBACK` through `executeRaw`. The transaction object's `commit()` and `rollback()` methods are lifecycle hooks: detach listeners and release the dedicated connection exactly once. They must not issue a second SQL commit/rollback.
```typescript
class ExampleTransaction extends ExampleQueryable implements Transaction {
readonly options = { usePhantomQuery: false }
#closed = false
constructor(connection: DriverConnection, private readonly release: () => void) {
super(connection)
}
async commit() { this.finish() }
async rollback() { this.finish() }
private finish() {
if (this.#closed) return
this.#closed = true
this.release()
}
async createSavepoint(name: string) {
await this.control(`SAVEPOINT ${safeSavepoint(name)}`)
}
async rollbackToSavepoint(name: string) {
await this.control(`ROLLBACK TO SAVEPOINT ${safeSavepoint(name)}`)
}
async releaseSavepoint(name: string) {
await this.control(`RELEASE SAVEPOINT ${safeSavepoint(name)}`)
}
private async control(sql: string) {
await this.executeRaw({ sql, args: [], argTypes: [] })
}
}
```
Implement the optional savepoint methods only where the provider supports them. Validate/quote savepoint identifiers. For providers whose savepoints are intentionally no-ops, document and test that limitation.
Never keep transaction depth on the shared adapter. Parallel transactions make adapter-global depth incorrect; nested state belongs to the returned transaction connection and Prisma's savepoint calls.
## Error mapping
Wrap recognized driver failures in `DriverAdapterError`. Map known conditions to `MappedError` kinds such as constraint violations, authentication/reachability, missing table/column/database, timeouts, closed transactions, invalid input, value range, and write conflicts.
For database errors, preserve `originalCode` and `originalMessage` even when falling back to the provider-specific raw variant:
```typescript
import {
DriverAdapterError,
type Error as DriverAdapterErrorObject,
type MappedError,
} from '@prisma/driver-adapter-utils'
function convertDriverError(error: DatabaseError): DriverAdapterErrorObject {
return {
originalCode: String(error.code),
originalMessage: error.message,
...mapKnownOrRaw(error),
}
}
function mapKnownOrRaw(error: DatabaseError): MappedError {
if (error.code === '23505') {
return { kind: 'UniqueConstraintViolation', constraint: parsedConstraint(error) }
}
return {
kind: 'postgres',
code: String(error.code ?? 'N/A'),
severity: error.severity ?? 'N/A',
message: error.message,
detail: error.detail,
column: error.column,
hint: error.hint,
}
}
function throwAdapterError(error: unknown): never {
if (!isDatabaseError(error)) throw error
throw new DriverAdapterError(convertDriverError(error))
}
```
Prisma uses preserved original details when an unmapped driver error becomes `P2039`. Do not replace every unknown exception with a fabricated `GenericJs` id; rethrow genuinely unexpected non-driver errors so programming bugs remain visible.
## Factory, ownership, and shadow database
- `connect()` returns a fresh usable adapter connection/pool wrapper.
- Track whether the factory created the pool. `dispose()` closes owned pools and only detaches listeners from caller-owned pools unless an explicit option transfers ownership.
- Implement `SqlMigrationAwareDriverAdapterFactory` only when `connectToShadowDb()` can create an isolated shadow database, connect to it, and drop it during disposal/failure cleanup.
- Never point the shadow adapter at the primary database. Quote generated identifiers and use cryptographically unique names.
- `getConnectionInfo()` should accurately report `schemaName`, `maxBindValues` when applicable, and `supportsRelationJoins`.
## Verification checklist
- [ ] Typecheck against the exact target `@prisma/driver-adapter-utils` version
- [ ] `queryRaw` preserves column order, types, nulls, and precision
- [ ] `executeRaw` reports affected rows correctly
- [ ] `executeScript` handles provider-specific multi-statement syntax
- [ ] Concurrent interactive transactions use distinct dedicated connections
- [ ] Success commits and releases once; failure rolls back and releases once
- [ ] Nested transaction tests exercise create/rollback/release savepoint hooks
- [ ] Unsupported isolation levels fail as `InvalidIsolationLevel`
- [ ] Known constraints map to structured errors
- [ ] Unmapped database errors retain original code/message and surface useful `P2039`
- [ ] Dispose ownership is tested for internal and external pools
- [ ] Shadow database creation, use, failure cleanup, and disposal are isolated
- [ ] Run Prisma Client integration/E2E tests, not only adapter unit tests
## Source references
- [Driver adapter interfaces](https://github.com/prisma/prisma/blob/v7/packages/driver-adapter-utils/src/types.ts)
- [PostgreSQL adapter transaction implementation](https://github.com/prisma/prisma/blob/v7/packages/adapter-pg/src/pg.ts)
- [PostgreSQL adapter error mapping](https://github.com/prisma/prisma/blob/v7/packages/adapter-pg/src/errors.ts)
@@ -0,0 +1,97 @@
---
name: prisma-mongodb-upgrade
description: Decision and migration guide for Prisma ORM MongoDB projects on v6, which have no upgrade path to v7. Use when a MongoDB project asks about upgrading Prisma, when "upgrade to prisma 7" comes up in a project with provider = "mongodb", or when evaluating a move to Prisma 8. Triggers on "upgrade prisma mongodb", "prisma 7 mongodb", "mongodb prisma migration", "prisma 8 mongodb".
license: MIT
metadata:
author: prisma
version: "0.2.0"
---
# Prisma MongoDB Upgrade Path
MongoDB projects are the one Prisma cohort with no road into Prisma 7: **v6 is the terminal
classic-ORM major for MongoDB, and v7 never ships a MongoDB connector**. The successor path
is Prisma 8, where MongoDB support is in [Early Access](https://www.prisma.io/docs/orm/supported-databases)
while PostgreSQL is a release candidate. The official
[Prisma ORM 6 to 8 (MongoDB) guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb)
is the source of truth for the migration steps. This skill frames the real decision — migrate to
Prisma 8 (the encouraged path), or stay on v6 where a hard blocker applies — and carries
the migration mechanics.
**Never do either of these:**
- Never advise a MongoDB project to "upgrade to Prisma 7". The connector does not exist
there. The `prisma-upgrade-v7` guide does not apply to MongoDB projects.
- Never solve the version question by rewriting the app onto a SQL database. Changing the
database engine is a separate, much larger decision that is not yours to make implicitly.
## The version landscape
| Version | MongoDB status |
|---------|----------------|
| Prisma ORM v6 | Fully supported (`mongodb` provider); latest 6.x is the current stable path; maintenance line |
| Prisma ORM v7 | **No MongoDB connector — not an option, ever** |
| Prisma 8 | MongoDB support in **Early Access** through `@prisma/orm-mongo`; still changes between release candidates — the successor path for MongoDB projects |
## The decision, up front
**Migrating to Prisma 8 is the encouraged path.** MongoDB support in Prisma 8 is Early
Access: functional and moving quickly — and the Prisma team wants MongoDB users to migrate
early and share feedback. The migration mechanics are
detailed in the references.
**Staying on the latest v6 remains a legitimate choice where a hard blocker applies** —
stated plainly: Prisma 8 has no MongoDB transaction method yet (multi-document writes use
the `mongodb` driver's sessions directly), and MongoDB behavior can still change between
Prisma 8 release candidates.
### Decision table
| Signal | Direction |
|--------|-----------|
| No blockers below apply | Migrate to Prisma 8; run the `verify-cutover-checklist` and share feedback with the Prisma team |
| Greenfield / prototype / internal tool | Migrate to Prisma 8 |
| Codebase uses multi-document transactions (`$transaction`) — check with grep, do not ask | Plan raw-driver session equivalents first (see `client-api-mapping`), or stay on v6 until Prisma 8 adds a MongoDB transaction method |
| Team cannot absorb breaking changes between release candidates | Stay on v6 until MongoDB support leaves Early Access |
| Risk-averse but interested | Point Prisma 8 at the v6 schema with `prisma6Schema(...)` (see `schema-contract-mapping`), rehearse on a copy (see `verify-cutover-checklist`), then migrate |
Note: this section will be updated when Prisma 8 adds a MongoDB transaction method.
### If staying on v6: hygiene (a deliberate stay, not neglect)
- Pin the Prisma packages to the latest 6.x line and keep taking 6.x patch releases.
- Track Prisma release notes and security advisories for the 6.x line.
- Keep the classic v6 MongoDB setup: `url = env("DATABASE_URL")` in the schema, `db push`
workflow, no SQL driver adapters (see [`prisma-orm-setup`](../prisma-orm-setup/references/v6-mongodb.md) for the v6 MongoDB shape).
- Re-evaluate when Prisma 8's MongoDB support leaves Early Access, or when the blockers are resolved.
## Reference files
| Reference | What it covers |
|-----------|----------------|
| `references/decision-stay-or-migrate.md` | The full decision framing, blocker checks, and stay-hygiene detail |
| `references/schema-contract-mapping.md` | v6 schema (`mongodb` provider, `@db.ObjectId`, composite types) → Prisma 8 contract concepts |
| `references/client-api-mapping.md` | v6 client calls → Prisma 8 equivalents, incl. raw escape hatches and transactions — names map, parity does not |
| `references/migrations-mapping.md` | v6 `db push`-only story → Prisma 8's plan/migrate/verify/sign flow |
| `references/verify-cutover-checklist.md` | No-data-moves verification: same DB, index parity, staged round-trip before cutover |
## Verified against
Prisma 8 claims in this skill were checked against the
[Prisma ORM 6 to 8 (MongoDB) guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb),
written for `@prisma/orm-mongo` 8.0.0-rc.13, and the `prisma-8` skill in
[prisma/orm](https://github.com/prisma/orm/tree/main/skills/prisma-8) at commit
`75c1460515fa2f11971533f6a1dec5dab35d4123`. MongoDB support still changes between release
candidates: **before acting on any Prisma 8 claim, check the installed version**
(`npm ls @prisma/orm-mongo`) and its synced `prisma-8` skill.
Prisma 8 on MongoDB requires Node.js 22.18+ (24.11+ on the 24 line; 24 recommended),
TypeScript 5.9+, MongoDB 8.0+, and `mongodb@7` as a peer dependency. The `mongodb@7` driver
no longer accepts AWS credentials in the connection string.
## Hand-off rule
This skill is the **discovery bridge**, not a replacement for Prisma 8's own
documentation. After a project switches to Prisma 8, run `prisma skills sync`, read the
synced `prisma-8/SKILL.md`, and follow it for day-to-day work — do not keep working from
this skill's summaries.
@@ -0,0 +1,75 @@
# client-api-mapping
How v6 Prisma Client calls map to Prisma 8's Mongo client — names map, parity does not.
## Priority
CRITICAL
## Why It Matters
The v6 and Prisma 8 client APIs look superficially similar, but none of the v6 MongoDB raw
methods exist under their old names, aggregation moved to a different lane entirely, and
transactions go through the driver rather than a Prisma method. Assuming parity produces
code that does not compile — or, in the transactions case, code that silently loses
atomicity.
## The mapping
| v6 call | Prisma 8 equivalent | Notes |
|---------|------------------------|-------|
| `prisma.user.findMany(...)` | `db.orm.users.where({ ... }).all()` | Chained API; collection-name keys (see `schema-contract-mapping.md`) |
| `prisma.user.findFirst(...)` | `db.orm.users.where({ ... }).first()` | `.where(...)` takes a plain equality object, not `{ equals: ... }` |
| `create` / `update` / `upsert` / `delete` | Same names on `db.orm.<collection>` | Every mutation except `create` needs a `.where(...)` first |
| `updateMany` / `deleteMany` | `updateAll` / `deleteAll` | |
| `prisma.user.aggregate(...)`, `groupBy(...)` | **No ORM equivalent.** Build a plan with `db.query.from(...).group(...).build()` and run it with `(await db.runtime()).query(plan)` | Group totals come from `acc` in `@prisma/orm-mongo/query-builder` |
| `<model>.findRaw(...)`, `<model>.aggregateRaw(...)` ([v6 docs](https://www.prisma.io/docs/orm/prisma-client/using-raw-sql/raw-queries#findraw)) | `db.raw.collection('<name>').aggregate([...]).build()`, or `db.query.rawCommand(...)` | Run the plan with `(await db.runtime()).query(plan)` |
| `$runCommandRaw(...)` ([v6 docs](https://www.prisma.io/docs/orm/prisma-client/using-raw-sql/raw-queries#runcommandraw)) | **No Prisma equivalent.** Create a `MongoClient`, pass it to the `mongo(...)` binding as `mongoClient`, and call `mongoClient.db(...).command(...)` | `db.raw` is collection-scoped; database-level commands go through the driver |
| `$transaction(...)` — works on v6 with a replica set ([v6 docs](https://www.prisma.io/docs/orm/overview/databases/mongodb#replica-set-configuration)) | **No Prisma method yet.** Use `mongodb` driver sessions (`client.startSession()` / `session.withTransaction(...)`) on a replica set | Pass `{ session }` to every operation; an operation without it runs outside the transaction |
| `$connect` / `$disconnect` | Connects lazily on first use; `db.close()` disconnects | |
**ObjectId filters in the pipeline builder:** `.match((f) => f.authorId.eq(authorId))` sends
the id as a plain string and matches nothing. Filter ObjectId fields through the ORM client
(`db.orm.posts.where({ authorId })`), or use `db.query.rawCommand(...)` with a real
`ObjectId`.
## Bad
```typescript
// Assuming v6 names exist in Prisma 8:
await db.users.$runCommandRaw({ collStats: 'users' }); // no such method
await db.transaction(async (tx) => { ... }); // no such method on the MongoDB client
```
## Good
```typescript
import { acc } from '@prisma/orm-mongo/query-builder';
// Aggregation through the typed pipeline builder:
const plan = db.query
.from('users')
.group((f) => ({ _id: f.role, n: acc.count() }))
.build();
const byRole = await (await db.runtime()).query(plan).toArray();
// Database-level commands through the MongoClient shared with the binding:
await mongoClient.db('my-app-db').command({ ping: 1 });
// Multi-document atomicity through a driver session:
const session = mongoClient.startSession();
try {
await session.withTransaction(async () => {
// ...writes, each with { session }...
});
} finally {
await session.endSession();
}
```
## References
- [Prisma ORM 6 to 8 (MongoDB) guide, step 3](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb#3-port-client-calls)
- [Prisma 8 transactions on MongoDB](https://www.prisma.io/docs/orm/fundamentals/transactions#transactions-on-mongodb)
- [v6 MongoDB raw queries](https://www.prisma.io/docs/orm/prisma-client/using-raw-sql/raw-queries#raw-queries-with-mongodb)
- The `prisma-8` skill's `references/queries-mongo.md` — authoritative for the Prisma 8 side
@@ -0,0 +1,86 @@
# decision-stay-or-migrate
How to decide between migrating a MongoDB project to Prisma 8 and staying on Prisma v6.
## Priority
CRITICAL
## Why It Matters
MongoDB projects cannot follow the general "upgrade Prisma" advice: Prisma 7 has no MongoDB
connector, so the forward path is Prisma 8. Advising an impossible v7 upgrade, or
silently rewriting the app onto SQL, are both serious failure modes. The encouraged path is
migrating to Prisma 8 — its MongoDB support is Early Access and the Prisma team wants
early adopters' feedback — with a deliberate stay on v6 where a hard blocker applies.
## The facts the decision rests on
Prisma 8 side ([supported databases](https://www.prisma.io/docs/orm/supported-databases),
[6 to 8 MongoDB guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb)):
- **MongoDB support is Early Access** in `@prisma/orm-mongo`; PostgreSQL is a release
candidate.
- The implementation is not a stub: an ORM client, a typed aggregation-pipeline builder, a
raw lane, and first-class contract-driven migrations.
- **Prisma 8 has no MongoDB transaction method yet** — there is no `db.transaction(...)` on
the MongoDB client. Multi-document atomicity uses the `mongodb` driver's session API on a
replica set. This skill will be updated when a transaction method ships.
- Early Access means MongoDB behavior can change between release candidates. Floor:
Node.js 22.18+, TypeScript 5.9+, MongoDB 8.0+, and `mongodb@7`.
Prisma v6 side:
- v6 fully supports MongoDB, including transactions on replica sets — "MongoDB only allows
you to start a transaction on a replica set. Prisma ORM uses transactions internally"
([replica set configuration](https://www.prisma.io/docs/orm/overview/databases/mongodb#replica-set-configuration)).
- v6 MongoDB has no Prisma Migrate; the workflow is `db push`
([no support for Prisma Migrate](https://www.prisma.io/docs/orm/overview/databases/mongodb#no-support-for-prisma-migrate)).
## Blocker checks before migrating
Run these checks yourself — from the codebase, not by asking the user:
- **Search the codebase for `$transaction` usage** (grep for `$transaction`). If present,
plan the raw-driver session equivalents before migrating (see `client-api-mapping.md`) —
or stay on v6 until Prisma 8 adds a MongoDB transaction method.
- **Check the MongoDB server version** (must be 8.0+ for Prisma 8; v6 tolerated older).
- **Confirm the team can absorb changes between release candidates.** Someone has to
follow the release notes and update the code. For a production app, confirm the user accepts
Early Access status before migrating.
## Bad
```text
User: "We're on Prisma 6 with MongoDB. Should we upgrade to Prisma 7?"
Agent: "Yes — here's the v7 upgrade guide. Step 1: install a driver adapter..."
```
Prisma 7 has no MongoDB connector; this migration is impossible and the SQL driver-adapter
steps corrupt a working v6 setup.
## Good
```text
User: "We're on Prisma 6 with MongoDB. Should we upgrade to Prisma 7?"
Agent: "Prisma 7 does not support MongoDB — v6 is the last classic-ORM
major for MongoDB. The path forward is Prisma 8, the successor: its MongoDB support is
Early Access and migrating is encouraged. Let me check the codebase for blockers first —
searching for $transaction usage and checking the MongoDB server version..."
```
## Stay-on-v6 hygiene
Staying is a decision, not a default-by-neglect:
- Pin `prisma` and `@prisma/client` to the latest 6.x and keep taking 6.x patches.
- Watch Prisma release notes and security advisories for the 6.x maintenance line.
- Keep the classic setup (`url = env("DATABASE_URL")` in the schema; `db push`; no SQL
driver adapters).
- Re-evaluate when Prisma 8's MongoDB support leaves Early Access, or when the blockers are resolved.
## References
- [Prisma ORM 6 to 8 (MongoDB) guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb)
- [Prisma 8 supported databases](https://www.prisma.io/docs/orm/supported-databases)
- [Prisma v6 MongoDB documentation](https://www.prisma.io/docs/orm/overview/databases/mongodb)
@@ -0,0 +1,83 @@
# migrations-mapping
How the v6 MongoDB "no migrations" story maps onto Prisma 8's first-class migration flow.
## Priority
HIGH
## Why It Matters
This is the largest workflow change in the migration — in v6, MongoDB explicitly has no
Prisma Migrate, while in Prisma 8 MongoDB participates in the full migration lifecycle.
Teams porting a `db push` habit into Prisma 8 without understanding the plan/verify/sign flow
will fight the tooling or bypass its safety rails.
## v6: `db push` only
MongoDB on v6 has no Prisma Migrate and no plans to add it — "MongoDB projects do not rely
on internal schemas" ([no support for Prisma Migrate](https://www.prisma.io/docs/orm/overview/databases/mongodb#no-support-for-prisma-migrate)).
The workflow is `prisma db push` to sync indexes and unique constraints, with no migration
history on disk.
## Prisma 8: bring the existing database under management
The database already has collections and data, so bootstrap it with `db update`. It diffs the
live database against the contract, applies the difference (strict validators, plus indexes
the contract declares that v6 never created), and signs the database:
```bash
npx prisma contract emit
npx prisma db update --db "$DATABASE_URL" --dry-run
npx prisma db update --db "$DATABASE_URL" --advance-ref db
```
`--advance-ref db` records the result as the `db` ref that later migration plans diff from.
**Do not use `db init` here.** It only applies additive changes, and adding a validator to a
collection with existing documents counts as destructive, so it refuses.
## Prisma 8: every later schema change
```bash
npx prisma contract emit
npx prisma migration plan --name add_posts_indexes
npx prisma db migrate --db "$DATABASE_URL" --advance-ref db
npx prisma db verify --db "$DATABASE_URL"
```
- **Declare, do not hand-write:** indexes and validators live in the contract, and
`migration plan` derives the operations. Rendered MongoDB migrations import their factories
(`createCollection`, `validatedCollection`, `setValidation`, `createIndex`, `dropIndex`,
`collMod`, `dataTransform`) from `@prisma/orm-mongo/target/migration`.
- **Marker storage:** Prisma 8 records the database's contract state in a document in the
`_prisma_migrations` collection.
- **DDL is not transactional on MongoDB:** an interrupted `db migrate` is resumed by running
it again. After fixing anything by hand, run `prisma db sign` so the signature matches the
database.
- **Push-style alternative:** `db update` without a migration plan is the `db push` analogue
for local experiments. It keeps no history.
- **Validators:** Prisma 8 adds strict `$jsonSchema` validators to each collection by default.
Once they are live, writes to documents that do not match the contract fail with
`Document failed validation`.
## Bad
```text
Porting the v6 habit: run `db update` for every change in production, accumulating no
migration history, and hand-editing collections when verification fails.
```
## Good
```text
Bootstrap once with `db update --advance-ref db`. Then emit the contract, plan a migration,
apply it with `db migrate`, and check with `db verify`. Reserve plain `db update` for local
experiments, mirroring how `db push` was used on v6.
```
## References
- [Prisma ORM 6 to 8 (MongoDB) guide, step 4](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb#4-adopt-the-migration-lifecycle)
- [v6: no Prisma Migrate for MongoDB](https://www.prisma.io/docs/orm/overview/databases/mongodb#no-support-for-prisma-migrate)
- The `prisma-8` skill's `references/migrations.md` — authoritative for the Prisma 8 side
@@ -0,0 +1,65 @@
# schema-contract-mapping
How v6 MongoDB schema concepts map onto Prisma 8's contract model.
## Priority
HIGH
## Why It Matters
Prisma 8 describes the database with a *contract* (authored in PSL or TypeScript), and
several v6 MongoDB idioms have different equivalents. Translating mechanically without
knowing the mapping produces contracts that fail `contract emit` or verification, or that
silently change collection addressing.
## Start without porting
Prisma 8 can read the v6 `schema.prisma` directly: set
`contract: prisma6Schema('prisma/schema.prisma')` in `prisma.config.ts`, with `prisma6Schema`
from `@prisma/orm-mongo/config`. v6 keeps owning the database; after each schema change there,
run `prisma contract emit` and `prisma db sign`. A construct Prisma 8 cannot express fails
`contract emit` with a `PSL.PRISMA6_MONGO_*` diagnostic. Port the schema to a contract when
you need what v6 syntax cannot express, such as polymorphism.
## The mapping
| v6 concept | Prisma 8 equivalent | Notes |
|------------|------------------------|-------|
| (nothing) | `// use prisma-8` as the first line of `contract.prisma` | Without it, `contract emit` fails with `CONTRACT.SOURCE_LOAD_FAILED` |
| `datasource db { provider = "mongodb" }` + `url = env(...)` ([v6 docs](https://www.prisma.io/docs/orm/overview/databases/mongodb#example)) | No provider in the contract. `prisma.config.ts` wraps `defineConfig` from `@prisma/orm-mongo/config` in `definePrismaConfig`, with `db.connection` | `prisma orm init --target mongodb` scaffolds it; point the connection at the same database v6 uses |
| `id String @id @default(auto()) @map("_id") @db.ObjectId` ([using ObjectId](https://www.prisma.io/docs/orm/overview/databases/mongodb#using-objectid)) | `id ObjectId @id @map("_id")` | |
| `Int`, `Float`, `Boolean`, `DateTime` | `Int32`, `Double`, `Bool`, `Date` | The v6 names still work with a `PSL_DEPRECATED_SCALAR_NAME` warning; a later release removes them |
| `BigInt`, `Decimal`, `Bytes`, `Json` | `Int64`, `Decimal128`, `Binary`, `Json` | `Json` holds only JSON values; type a field that holds other BSON values, such as a `Date`, as `Bson` |
| `@default(now())`, `@updatedAt` | `temporal.createdAt()`, `temporal.updatedAt()` | |
| Composite types: `type Address { ... }` ([composite types](https://www.prisma.io/docs/orm/prisma-client/special-fields-and-types/composite-types)) | `type Address { ... }` | Unchanged |
| Enums read and written by key | Enums read and write their **storage value** (`role: 'author'`, not `'Author'`) | Declare the storage value in the enum, for example `Author = "author"` |
| Model names address the client (`prisma.user`) | **Collection names** address the ORM: `db.orm.users` — the `@@map(...)` value, or the model name exactly as written when there is no `@@map`. `db.orm.User` does not exist for a model mapped to `users` | The most common porting mistake |
| Indexes declared in schema, applied by `db push` | `@@index(...)` / `@@unique(...)` in the contract, applied by migrations | See `migrations-mapping.md` |
| No native polymorphism | `@@discriminator(field)` on the base model and `@@base(Base, "value")` on each variant | Declare a variant for **every** value the field has in existing data: the generated validator rejects writes to documents with an undeclared value. A variant must declare at least one field |
## Bad
```typescript
// Ported from v6 and addressed by model name:
const user = await db.orm.User.where({ email }).first(); // no such key — the collection is mapped to "users"
```
## Good
```typescript
// Mongo ORM keys are collection names (@@map value, or the model name as written):
const user = await db.orm.users.where({ email }).first();
```
## Environment requirements
Prisma 8 on MongoDB requires MongoDB 8.0+ and `mongodb@7` as a peer dependency. v6 supports
older MongoDB servers, so check the server version before planning a migration.
## References
- [Prisma ORM 6 to 8 (MongoDB) guide, step 2](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb#2-port-the-schema-to-a-contract)
- [v6 MongoDB schema documentation](https://www.prisma.io/docs/orm/overview/databases/mongodb)
- [v6 composite types (MongoDB-only)](https://www.prisma.io/docs/orm/prisma-client/special-fields-and-types/composite-types)
- The `prisma-8` skill's `references/contract.md` — authoritative for the Prisma 8 side
@@ -0,0 +1,60 @@
# verify-cutover-checklist
Verification checklist for a v6 → Prisma 8 cutover: the data never moves — only the code does.
## Priority
CRITICAL
## Why It Matters
A v6 → Prisma 8 migration is a *client and workflow* migration against the **same MongoDB
database** — there is no data export/import step, and introducing one (or pointing the new
stack at a fresh database) turns a code migration into an outage. The checklist below keeps
the cutover observable and reversible.
## Ground rules
- **No data moves.** The Prisma 8 contract is authored to describe the existing collections;
both stacks read the same database during the staged phase.
- **v6 stays runnable until cutover is verified.** Do not delete the v6 client, schema, or
dependencies until the checklist passes.
## Checklist
1. **Same database, verified:** the Prisma 8 config points at the same connection string /
database name the v6 app uses. The `mongodb@7` driver rejects some URLs v6 accepted, such
as AWS credentials in the connection string — validate the URL with the driver first.
2. **Server floor:** MongoDB server is 8.0+ (Prisma 8's requirement; v6 tolerated older).
Confirm before authoring any contract.
3. **Rehearsal on a copy:** on a throwaway copy of the database, run `contract emit`,
`db update --dry-run`, `db update`, and `db verify`, and confirm `db verify` passes before
touching production. Verification failures here are contract-mapping bugs, not database
problems.
4. **Index parity:** enumerate indexes on every collection (`db.collection.getIndexes()`)
and confirm the Prisma 8 contract declares the same set — v6 `db push` may have created
indexes the new contract must re-declare, or verification and query performance will
diverge.
5. **Validator impact assessed:** Prisma 8 emits closed `$jsonSchema` validators by default;
confirm legacy documents (extra fields, drifted shapes) pass them on the staging copy
before applying to production.
6. **Storage-name addressing audited:** every ported call site uses collection storage
names (`db.orm.users`), not model names (see `schema-contract-mapping.md`).
7. **Transaction inventory mapped:** grep the v6 app for `$transaction`; each hit gets a
`mongodb` driver-session equivalent on a replica set (see `client-api-mapping.md`).
8. **Raw call inventory mapped:** every `$runCommandRaw` / `findRaw` / `aggregateRaw` call
has an explicit Prisma 8 replacement (`db.raw`, `db.query.rawCommand(...)`, the pipeline
builder, or the shared `MongoClient`).
9. **Staged read-only soak:** run the Prisma 8 stack read-only against staging/production data
alongside v6 and compare outputs before allowing writes.
10. **Cutover + rollback:** switch writes to Prisma 8 only after the soak; keep the v6 branch
deployable as the rollback path. Rolling back is a code rollback — the data was never
moved.
After cutover, follow the synced `prisma-8` skill for ongoing work (see the hand-off rule
in `SKILL.md`).
## References
- [v6 MongoDB documentation](https://www.prisma.io/docs/orm/overview/databases/mongodb)
- [Prisma ORM 6 to 8 (MongoDB) guide, step 5](https://www.prisma.io/docs/guides/upgrade-prisma-orm/mongodb#5-pre-flight-checklist-before-production-cutover)
@@ -0,0 +1,82 @@
---
name: prisma-orm-setup
description: Set up Prisma ORM in an application, connect its database, or troubleshoot the connection of an existing Prisma 6, 7, or 8 app. Defaults new applications to Prisma ORM 8 and loads the package-owned prisma-8 skill; keeps existing Prisma 6/7 apps on their version with provider references for PostgreSQL, MySQL, SQLite, SQL Server, CockroachDB, MongoDB, and Prisma Postgres.
license: MIT
metadata:
author: prisma
version: "1.0.0"
---
# Prisma ORM setup
This skill owns ORM version selection for setup and connection work. Preserve the application's ORM version and intended database. A connection repair does not require a major upgrade.
New applications default to **Prisma ORM 8**. Detailed Prisma 8 configuration, queries, migrations, and runtime code belong to the versioned [prisma-8 skill](https://github.com/prisma/orm/tree/main/skills/prisma-8) shipped with the ORM package.
## 1. Detect the starting point
Read the package manifest, lockfile, Prisma configuration, schema, and application imports. Identify the ORM version, database provider, and runtime. The CLI version alone does not identify the application's version: a Prisma 8 CLI can coexist with a legacy client, so inspect `@prisma/client`, `@prisma/prisma7`, and the schema and configuration.
| Starting point | Path |
| ------------------------------------------------------- | -------------------------------------------------------- |
| Prisma 8 application | Step 4, without reinitializing |
| New application without a version choice | Step 3 |
| Prisma 6 or 7 application, or an explicit earlier major | [Step 5](#5-set-up-or-repair-an-earlier-version) |
For a new application, check the selected Prisma 8 release's [provider support](https://www.prisma.io/docs/orm/supported-databases) and runtime requirements before installing. If the provider is unsupported, explain the limitation and offer an explicitly selected earlier version. Keep the requested database; do not silently fall back or invent a supported target.
Use an existing database when supplied. Load `prisma-postgres-setup` only when Prisma Postgres is needed and no connection has been selected yet; return here once connected.
## 2. Handle requested major upgrades separately
When the user requests a major upgrade, load a workflow that supports the source version and provider. For PostgreSQL 7-to-8, use the [Prisma migration guide](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql); for MongoDB 6-to-8, use [prisma-mongodb-upgrade](../prisma-mongodb-upgrade/SKILL.md). Other providers need an explicitly supported migration path. `prisma-upgrade-v7` covers **6 to 7**; the package-owned `prisma-8` upgrade reference covers updates within 8.
## 3. Bootstrap a new Prisma 8 application
Check the selected release's [runtime requirements](https://www.prisma.io/docs/orm/release-status) and [initialization guide](https://www.prisma.io/docs/cli/orm-init). Resolve and pin a published Prisma CLI **8** release, including its prerelease suffix if needed; verify its version before initialization. Do not rely on a floating `latest` remaining version 8.
Use the project's package manager to run the installed CLI. For PostgreSQL and Prisma schema language authoring:
```bash
prisma orm init --yes --target postgres --authoring psl
```
Use the supported target for the selected provider. Preserve existing application files and connection configuration; do not let setup provision an unrelated database. Verify that the resolved ORM package is version 8 before proceeding.
## 4. Load the installed Prisma 8 guidance
Run the installed CLI through the project's package manager:
```bash
prisma skills sync
```
Then **read** the synced `prisma-8/SKILL.md`, for example `.agents/skills/prisma-8/SKILL.md`, and follow its preconditions and selected references. Syncing alone does not load the instructions. If the package-owned guidance cannot be loaded, report the blocker. Continue with step 6.
## 5. Set up or repair an earlier version
For a new setup that explicitly selects an earlier version, pin packages to that major and use its runtime requirements. Keep the CLI, client, and SQL adapter releases compatible. Existing dependencies need not change for a connection repair.
- **Prisma 7 SQL:** use the provider reference below and [client setup](references/v7-client-setup.md).
- **Prisma 6 MongoDB:** use [MongoDB setup](references/v6-mongodb.md). SQL driver adapters do not apply.
- **Prisma 6 SQL:** preserve its generator, schema URL, and client initialization. Use the provider's connection details below and the [Prisma 6 documentation](https://www.prisma.io/docs/orm/v6); do not copy the Prisma 7 configuration or adapter examples into it.
| Database | Reference |
| -------------------------------- | --------------------------------------------------------- |
| PostgreSQL | [PostgreSQL](references/v7-postgresql.md) |
| MySQL / MariaDB / PlanetScale | [MySQL](references/v7-mysql.md) |
| SQLite / Turso | [SQLite](references/v7-sqlite.md) |
| Microsoft SQL Server / Azure SQL | [SQL Server](references/v7-sqlserver.md) |
| CockroachDB | [CockroachDB](references/v7-cockroachdb.md) |
| MongoDB / Atlas on Prisma 6 | [MongoDB](references/v6-mongodb.md) |
| Prisma Postgres with Prisma 7 | [Prisma Postgres](references/v7-prisma-postgres.md) |
The Prisma 7 SQL examples were verified with Prisma 7.10.0; the MongoDB examples with Prisma 6.19.3.
## 6. Connect and verify
The CLI and the application can load different environment files. Load the intended environment for each without printing secrets, and keep credentials in ignored environment files or the host's secret configuration. For SQL adapters, make the adapter's runtime options address the same database as the CLI connection URL.
For an existing app, preserve schema, migrations, and generator configuration unless the requested work requires changes. Diagnose the connection before running schema-changing commands.
Run the project's relevant checks and a read-only query through the application's client against the intended database. Report the ORM version, the loaded `prisma-8` skill version where applicable, and the query result. Package installation or a successful skill sync alone is not a completed setup.
@@ -0,0 +1,102 @@
# MongoDB Setup
This reference configures **Prisma ORM 6 MongoDB** applications. Preserve an existing Prisma 6 app or use this path when 6 is explicitly selected. Do not apply Prisma 7 SQL adapters here.
## Prerequisites
- MongoDB 4.2+
- Replica Set configured (required for transactions)
- Latest Prisma 6.x release, or your team's pinned Prisma 6 version
- A Node.js and TypeScript version supported by the selected Prisma 6 release
## 1. Schema Configuration
Use the standard Prisma 6 MongoDB setup with `prisma-client-js`.
In `prisma/schema.prisma`:
```prisma
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
```
### Driver Adapters
Do **not** apply the Prisma 7 SQL adapter setup here. MongoDB does not use a SQL `@prisma/adapter-*` package.
### ID Field Requirement
MongoDB models **must** have a mapped `_id` field using `@id` and `@map("_id")`, usually of type `String` with `auto()` and `db.ObjectId`.
```prisma
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String?
posts Post[]
}
```
### Relations
Relations in MongoDB expect IDs to be `db.ObjectId` type.
```prisma
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
}
```
## 2. Environment Variable
In `.env`:
```env
DATABASE_URL="mongodb+srv://user:password@cluster.mongodb.net/mydb?retryWrites=true&w=majority"
```
## Migrations vs Introspection
- **No Migrations**: MongoDB is schema-less. `prisma migrate` commands **do not work**.
- **db push**: Use `prisma db push` to sync indexes and constraints.
- **db pull**: Use `prisma db pull` to generate schema from existing data (sampling).
## Client setup
Keep existing pinned versions. For a new explicitly selected Prisma 6 setup:
```bash
npm install --save-dev prisma@6
npm install @prisma/client@6 dotenv
```
Generate with the matching CLI, then initialize the client without a SQL adapter:
```typescript
import 'dotenv/config'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
```
Use a read-only model query to verify connectivity. Review any index changes before applying `db push` to an existing database.
## Common Issues
### "Transactions not supported"
Ensure your MongoDB instance is a **Replica Set**. Standalone instances do not support transactions. Atlas clusters are replica sets by default.
### "Invalid ObjectID"
Ensure fields referencing IDs are decorated with `@db.ObjectId` if the target is an ObjectID.
## References
- [Prisma 6 MongoDB connector](https://www.prisma.io/docs/orm/v6/overview/databases/mongodb)
@@ -0,0 +1,50 @@
# Prisma Client Setup
Generate and instantiate **Prisma ORM 7** Client for SQL providers. For MongoDB, follow [Prisma 6 MongoDB setup](v6-mongodb.md). For an existing Prisma 6 SQL app, preserve its client setup rather than copying these examples.
## 1. Install dependencies
```bash
npm install --save-dev prisma@7
npm install @prisma/client@7 dotenv
```
For an existing application, retain its pinned releases. For a new Prisma 7 application, use compatible CLI, client, and adapter versions and check the [Prisma 7 runtime requirements](https://www.prisma.io/docs/guides/upgrade-prisma-orm/v7#prerequisites).
## 2. Add generator block
In `prisma/schema.prisma`:
```prisma
generator client {
provider = "prisma-client"
output = "../generated"
}
```
`prisma-client` requires an explicit `output` path and does not generate into `node_modules` by default.
## 3. Generate Prisma Client
```bash
npx prisma generate
```
Re-run `prisma generate` after every schema change to keep the client in sync.
## 4. Instantiate Prisma Client
```typescript
import 'dotenv/config'
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL })
const prisma = new PrismaClient({ adapter })
```
If you change the generator `output`, update the import path to match. For the SQL provider workflow, replace `PrismaPg` with the adapter for your database.
## 5. Use a single instance
Each `PrismaClient` instance creates a connection pool. Reuse a single instance per app process to avoid exhausting database connections.
@@ -0,0 +1,94 @@
# CockroachDB Setup
Configure **Prisma ORM 7** with CockroachDB. For an existing Prisma 6 app, keep its configuration and use the [Prisma 6 docs](https://www.prisma.io/docs/orm/v6); the configuration and adapter examples below are for 7.
## Prerequisites
- CockroachDB cluster
## 1. Schema Configuration
In `prisma/schema.prisma`:
```prisma
datasource db {
provider = "cockroachdb"
}
generator client {
provider = "prisma-client"
output = "../generated"
}
```
## 2. Config Configuration
In `prisma.config.ts`:
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: env('DATABASE_URL'),
},
})
```
## 3. Environment Variable
In `.env`:
```env
DATABASE_URL="postgresql://user:password@host:26257/db?sslmode=verify-full"
```
Note: CockroachDB uses the PostgreSQL wire protocol, so the URL often looks like postgresql, but the provider **MUST** be `cockroachdb` in the schema to handle specific CRDB features correctly.
## Driver Adapter
Use a driver adapter for the standard SQL workflow. CockroachDB is PostgreSQL-compatible, so use the PostgreSQL adapter.
1. Install adapter and driver:
```bash
npm install @prisma/adapter-pg@7 pg
```
2. Instantiate Prisma Client with the adapter:
```typescript
import 'dotenv/config'
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL })
const prisma = new PrismaClient({ adapter })
```
## ID Generation
CockroachDB uses `BigInt` or `UUID` for IDs efficiently.
```prisma
model User {
id BigInt @id @default(autoincrement()) // Uses unique_rowid()
}
```
Or using string UUIDs:
```prisma
model User {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
}
```
## Common Issues
### Schema Introspection
Always use `provider = "cockroachdb"` to ensure correct type mapping during `db pull`.
## References
- [Prisma 7 CockroachDB documentation](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/cockroachdb)
@@ -0,0 +1,132 @@
# MySQL Setup
Configure **Prisma ORM 7** with MySQL and MariaDB. For an existing Prisma 6 app, keep its configuration and use the [Prisma 6 docs](https://www.prisma.io/docs/orm/v6); the configuration and adapter examples below are for 7.
## Prerequisites
- MySQL or MariaDB database
- Connection string
## 1. Schema Configuration
In `prisma/schema.prisma`:
```prisma
datasource db {
provider = "mysql"
}
generator client {
provider = "prisma-client"
output = "../generated"
}
```
## 2. Config Configuration
In `prisma.config.ts`:
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: env('DATABASE_URL'),
},
})
```
## 3. Environment Variable
In `.env`:
```env
DATABASE_URL="mysql://user:password@localhost:3306/mydb"
```
### Connection String Format
```
mysql://USER:PASSWORD@HOST:PORT/DATABASE
```
- **USER**: Database user
- **PASSWORD**: Password
- **HOST**: Hostname
- **PORT**: Port (default 3306)
- **DATABASE**: Database name
## Driver Adapter
Use a driver adapter for the standard SQL workflow.
1. Install adapter and driver:
```bash
npm install @prisma/adapter-mariadb@7 mariadb
```
2. Set `MYSQL_USER`, `MYSQL_PASSWORD`, and `MYSQL_DATABASE` in the application environment to match the CLI URL, and use the same host and port. Instantiate Prisma Client with the adapter:
```typescript
import 'dotenv/config'
import { PrismaClient } from '../generated/client'
import { PrismaMariaDb } from '@prisma/adapter-mariadb'
const adapter = new PrismaMariaDb({
host: 'localhost',
port: 3306,
connectionLimit: 5,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
})
const prisma = new PrismaClient({ adapter })
```
### Text protocol option
If you need the MariaDB driver's text protocol instead of the default binary `execute()` path, enable `useTextProtocol` explicitly:
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaMariaDb } from '@prisma/adapter-mariadb'
const adapter = new PrismaMariaDb(process.env.DATABASE_URL!, {
useTextProtocol: true,
})
const prisma = new PrismaClient({ adapter })
```
Use this only when you specifically need text-protocol compatibility for your MariaDB setup.
## PlanetScale Setup
Check whether foreign key constraints are enabled on the PlanetScale database. When they are disabled, use `relationMode = "prisma"` and add indexes for relation fields. Do not override an existing database that has foreign keys enabled.
In `prisma/schema.prisma`:
```prisma
datasource db {
provider = "mysql"
relationMode = "prisma" // Emulate foreign keys in Prisma
}
```
## Common Issues
### "Too many connections"
Set `connectionLimit` on `PrismaMariaDb`, as in the example above. The Prisma 6 `connection_limit` URL parameter does not configure the Prisma 7 adapter pool.
### JSON Support
MySQL 5.7+ supports JSON. MariaDB 10.2+ supports JSON (as an alias for LONGTEXT with check constraints). Prisma handles this, but verify your version.
## References
- [Prisma 7 connection pool settings](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections/connection-pool)
- [PlanetScale foreign key configuration](https://www.prisma.io/docs/orm/v7/overview/databases/planetscale)
- [Prisma 7 MySQL and MariaDB documentation](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/mysql)
@@ -0,0 +1,97 @@
# PostgreSQL Setup
Configure **Prisma ORM 7** with PostgreSQL. For an existing Prisma 6 app, keep its configuration and use the [Prisma 6 docs](https://www.prisma.io/docs/orm/v6); the configuration and adapter examples below are for 7.
## Prerequisites
- PostgreSQL database (local or cloud)
- Connection string
## 1. Schema Configuration
In `prisma/schema.prisma`:
```prisma
datasource db {
provider = "postgresql"
}
generator client {
provider = "prisma-client"
output = "../generated"
}
```
## 2. Config Configuration
In `prisma.config.ts`:
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: env('DATABASE_URL'),
},
})
```
## 3. Environment Variable
In `.env`:
```env
DATABASE_URL="postgresql://user:password@localhost:5432/mydb?schema=public"
```
### Connection String Format
```
postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=SCHEMA
```
- **USER**: Database user
- **PASSWORD**: Password (URL encoded if special chars)
- **HOST**: Hostname (localhost, IP, or domain)
- **PORT**: Port (default 5432)
- **DATABASE**: Database name
- **SCHEMA**: Schema name (default `public`)
## Driver Adapter
Use a driver adapter for the standard SQL workflow.
1. Install adapter and driver:
```bash
npm install @prisma/adapter-pg@7 pg
```
2. Instantiate Prisma Client with the adapter:
```typescript
import 'dotenv/config'
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL })
const prisma = new PrismaClient({ adapter })
```
## Common Issues
### "Can't reach database server"
- Check host and port
- Check firewall settings
- Ensure database is running
### "Authentication failed"
- Check user/password
- Special characters in password must be URL-encoded
### "Schema does not exist"
- Ensure `?schema=public` (or your schema) is in the URL
## References
- [Prisma 7 PostgreSQL documentation](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/postgresql)
@@ -0,0 +1,32 @@
# Prisma Postgres with Prisma ORM 7
Use this reference for an existing or explicitly selected **Prisma ORM 7** app. Obtain or reuse the database through [prisma-postgres-setup](../../prisma-postgres-setup/SKILL.md).
## Node.js connections
Use the PostgreSQL TCP connection supplied by Prisma Console or the integration and follow [PostgreSQL setup](v7-postgresql.md). Use a pooled or direct connection according to the intended operation. A `prisma+postgres://` Accelerate URL is not a TCP connection string for `PrismaPg`.
## Edge connections
For a runtime without PostgreSQL TCP support, Prisma Postgres provides an HTTP/WebSocket driver. With a Prisma 7 client:
```bash
npm install @prisma/adapter-ppg@7 @prisma/ppg
```
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaPostgresAdapter } from '@prisma/adapter-ppg'
const prisma = new PrismaClient({
adapter: new PrismaPostgresAdapter({
connectionString: process.env.DATABASE_URL!,
}),
})
```
The serverless driver takes a direct Prisma Postgres connection string as its credential and communicates over HTTP/WebSockets. It does not open a TCP connection. Load secrets through the host's supported mechanism and set the Prisma 7 generator's `runtime` to that deployment target.
These adapter examples do not configure Prisma 8. Its runtime guidance belongs to the installed `prisma-8` skill.
See the [Prisma Postgres serverless driver documentation](https://www.prisma.io/docs/postgres/database/serverless-driver) for connection selection and supported runtimes.
@@ -0,0 +1,114 @@
# SQLite Setup
Configure **Prisma ORM 7** with SQLite. For an existing Prisma 6 app, keep its configuration and use the [Prisma 6 docs](https://www.prisma.io/docs/orm/v6); the configuration and adapter examples below are for 7.
## Prerequisites
- None (file-based)
## 1. Schema Configuration
In `prisma/schema.prisma`:
```prisma
datasource db {
provider = "sqlite"
}
generator client {
provider = "prisma-client"
output = "../generated"
}
```
## 2. Config Configuration
In `prisma.config.ts`:
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: env('DATABASE_URL'),
},
})
```
## 3. Environment Variable
In `.env`:
```env
DATABASE_URL="file:./dev.db"
```
### Connection String Format
```
file:PATH
```
- **PATH**: Relative path to the database file. Check `prisma.config.ts` if you need to confirm how your app resolves it.
## Driver Adapter
Use a driver adapter for the standard SQL workflow.
1. Install adapter and driver:
```bash
npm install @prisma/adapter-better-sqlite3@7 better-sqlite3
```
2. Instantiate Prisma Client with the adapter:
```typescript
import 'dotenv/config'
import { PrismaClient } from '../generated/client'
import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3'
const adapter = new PrismaBetterSqlite3({
url: process.env.DATABASE_URL!,
})
const prisma = new PrismaClient({ adapter })
```
## Using Driver Adapter (LibSQL / Turso)
For edge compatibility or Turso:
1. Install:
```bash
npm install @prisma/adapter-libsql@7 @libsql/client
```
2. Instantiate:
```typescript
import 'dotenv/config'
import { PrismaClient } from '../generated/client'
import { PrismaLibSql } from '@prisma/adapter-libsql'
const adapter = new PrismaLibSql({
url: process.env.TURSO_DATABASE_URL,
authToken: process.env.TURSO_AUTH_TOKEN,
})
const prisma = new PrismaClient({ adapter })
```
## Limitations
- **Enums**: Prisma supports enum fields, but SQLite does not enforce enum values at the database level.
- **No Scalar Lists**: `String[]` is not supported directly.
- **Concurrency**: Write operations lock the file.
## Common Issues
### "Database file not found"
Check the resolved file path for both the CLI and the runtime adapter; relative paths can resolve differently. Use an explicit path to the intended file rather than silently creating a second database.
## References
- [Prisma 7 SQLite documentation](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sqlite)
@@ -0,0 +1,101 @@
# SQL Server Setup
Configure **Prisma ORM 7** with SQL Server. For an existing Prisma 6 app, keep its configuration and use the [Prisma 6 docs](https://www.prisma.io/docs/orm/v6); the configuration and adapter examples below are for 7.
## Prerequisites
- SQL Server 2017, 2019, 2022, or Azure SQL
- TCP/IP enabled
## 1. Schema Configuration
In `prisma/schema.prisma`:
```prisma
datasource db {
provider = "sqlserver"
}
generator client {
provider = "prisma-client"
output = "../generated"
}
```
## 2. Config Configuration
In `prisma.config.ts`:
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: env('DATABASE_URL'),
},
})
```
## 3. Environment Variable
In `.env`:
```env
DATABASE_URL="sqlserver://localhost:1433;database=mydb;user=sa;password=Password123;encrypt=true;trustServerCertificate=true"
```
### Connection String Format
```
sqlserver://HOST:PORT;database=DB;user=USER;password=PASS;encrypt=true;trustServerCertificate=true
```
- **encrypt**: Required for Azure (true).
- **trustServerCertificate**: True for self-signed certs (local dev).
## Driver Adapter
Use a driver adapter for the standard SQL workflow.
1. Install adapter and driver:
```bash
npm install @prisma/adapter-mssql@7 mssql
```
2. Set `SQLSERVER_USER` and `SQLSERVER_PASSWORD` in the application environment to match the CLI URL, and use the same server, port, database, and TLS options. The following example is for local development with a self-signed certificate; use certificate verification for hosted databases. Instantiate Prisma Client with the adapter:
```typescript
import 'dotenv/config'
import { PrismaClient } from '../generated/client'
import { PrismaMssql } from '@prisma/adapter-mssql'
const adapter = new PrismaMssql({
server: 'localhost',
port: 1433,
database: 'mydb',
user: process.env.SQLSERVER_USER,
password: process.env.SQLSERVER_PASSWORD,
options: {
encrypt: true,
trustServerCertificate: true,
},
})
const prisma = new PrismaClient({ adapter })
```
## Common Issues
### "Login failed for user"
- SQL Server auth vs Windows auth. Prisma typically uses SQL Server authentication (username/password).
- Ensure TCP/IP is enabled in SQL Server Configuration Manager.
### "Table not found" (dbo schema)
Check that the connection URL's `schema` parameter (normally `dbo`) matches the intended schema. Preserve an existing multi-schema configuration and model mappings.
## References
- [Prisma 7 SQL Server documentation](https://www.prisma.io/docs/orm/v7/core-concepts/supported-databases/sql-server)
@@ -0,0 +1,47 @@
---
name: prisma-postgres-setup
description: Obtain or reuse a Prisma Postgres database and connect an application. Use when the user needs a database and has none configured ("I need a database", "add a Postgres database", "set up a database for this app"), runs or mentions `create-db` or `npx create-db`, or asks to set up or connect Prisma Postgres, including in v0 and the Vercel Marketplace. Hands Prisma ORM configuration to prisma-orm-setup; reuses an existing connection first and honors an explicit provider, driver, alternative ORM, or database-only choice.
license: MIT
metadata:
author: prisma
version: "2.2.0"
---
# Prisma Postgres setup
Connect the intended database, then verify it from the application. Keep provisioning separate from ORM configuration so an existing database is reused.
## 1. Inspect the project
Check the user's requested ORM or driver, installed packages, database connection, and environment-loading files. Check secret presence without printing values.
- Honor explicit choices such as Drizzle, `pg`, or database-only setup.
- For query or schema work in an already configured app, use its version-matched ORM guidance; do not restart setup.
## 2. Reuse or obtain a database
| Situation | Action |
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Existing connection or connected integration | Verify its project, database, and environment; reuse it. |
| v0, Vercel Marketplace, or a Vercel project | Read [Marketplace setup](references/vercel-marketplace.md) and use the native integration flow. |
| No database yet and no provider named | Offer `npx create-db@latest` for a working database now with no account (it is deleted after 24 hours unless claimed, and claiming needs a free Prisma account; read the create-db section in [provisioning](references/provisioning.md)), or a persistent database through [provisioning](references/provisioning.md). Ask which one when the request does not say. |
| Standalone persistent database | Read [provisioning](references/provisioning.md); use an authenticated CLI, MCP tool, Console, or Management API. |
| Temporary development database requested | Read the `create-db` section in [provisioning](references/provisioning.md), including expiry and claiming. |
Resolve the workspace, project, and region before creation. If several resources fit, ask which one to use. If provisioning is blocked by permissions or quota, report the blocker; do not delete another resource or switch workspaces to get around it.
## 3. Connect the application
Use the connection appropriate to the chosen driver and runtime. Store it in the project's secret environment configuration, never source code or chat. Preserve unrelated entries, update the intended variable once, and ensure local secret files are ignored by Git.
Application processes and CLI commands may load different environment files. For example, a framework may load `.env.development.local` while a shell command does not. A variable missing from the shell does not mean the database is missing: load the intended file for that command without displaying credentials, and do not provision another database.
## 4. Configure the ORM and verify
For Prisma ORM setup, read [prisma-orm-setup/SKILL.md](https://github.com/prisma/skills/blob/main/prisma-orm-setup/SKILL.md) directly, or load the installed `prisma-orm-setup` skill when the host resolves sibling skills by name. It owns ORM version selection and configuration. If that handoff is unavailable, report it.
For an explicitly selected alternative, keep that ORM or driver and use its documented setup. For database-only setup, stop after verifying connectivity.
Run a read-only query against the intended database through the application's chosen ORM or driver. Report what was connected, the selected ORM/version, and the query result without secrets. If any step is blocked or untested, say so instead of claiming setup is complete.
For Studio, SDK integrations, or database operations beyond initial setup, read [operations](references/operations.md).
@@ -0,0 +1,20 @@
# Console and programmatic operations
Read this only for work beyond connecting one application.
## Console and database operations
Use [Prisma Console](https://console.prisma.io) to inspect the selected project and open its database in Studio. Use links returned by the API or UI rather than constructing Console URLs from guessed ID formats.
For usage, backups, connections, or restoration, inspect current Platform CLI help or the [Management API schema](https://api.prisma.io/v1/doc). Resolve resource IDs before acting. Database deletion, restoration, and credential revocation are separate actions requiring the user's authorization; they are not routine setup steps.
## Management API SDK
Use `@prisma/management-api-sdk` for a typed API integration. Its installed types define current routes and request/response shapes independently of ORM versions.
- `createManagementApiClient({ token })` uses an existing token. Check HTTP errors before reading response data and follow pagination on collection routes.
- `createManagementApiSdk(...)` supports OAuth and token refresh. Implement persistent, protected token storage; do not copy a no-op storage example into an application.
- In the OAuth flow, persist and validate state and the verifier, handle the callback, and store refreshed tokens securely.
- Service-token and connection creation can return credentials once. Save them to the intended secret store without logging the response. Listing token metadata does not recover the original value.
For exact interfaces and a complete integration, use the [SDK documentation](https://www.prisma.io/docs/postgres/introduction/management-api-sdk) and installed package types. Keep ORM schema and migration work in the version-matched ORM skill.
@@ -0,0 +1,43 @@
# Standalone provisioning
First reuse an existing connection or resource. For v0 or Vercel Marketplace, use the [native integration flow](vercel-marketplace.md) instead.
## Persistent databases
Choose an available authenticated surface: Prisma Console, the Prisma Platform CLI, a connected Prisma MCP server, or the Management API. Reuse existing authentication; do not ask the user to paste tokens into chat.
- **Console:** select the intended workspace and project at [Prisma Console](https://console.prisma.io), then obtain the database's connection details.
- **Platform CLI:** inspect the current command help before mutation. The Platform commands ship in the Prisma 8 CLI (`prisma` 8, also published as `@prisma/cli`); the `postgres` group of a Prisma 7 `prisma` binary only links an existing database. Start with `npx -y @prisma/cli@latest postgres --help`; discover list, create, and connection commands from that version.
- **MCP:** discover available tools and their input schemas. Confirm the workspace and resource context before invoking a provisioning tool. Missing tools or authentication are blockers, not permission to switch accounts.
- **Management API:** use the [current schema](https://api.prisma.io/v1/doc) at `https://api.prisma.io/v1`, or installed SDK types, for exact endpoints and payloads. Do not copy an older project/database response shape blindly.
List available regions and select one consistent with the user's location requirements and application. Resolve the intended workspace, project, and, where required, branch before creating a database. Follow pagination when listing resources. If creation is asynchronous, poll the returned resource until ready with a bounded wait; report a timeout without creating a replacement. Before retrying an ambiguous creation request, check whether it succeeded to avoid duplicates.
Store returned connection credentials immediately in the intended secret environment. Some credentials are shown only once. Select the direct or pooled endpoint appropriate to the chosen driver and runtime; inspect the returned connection details instead of assuming every endpoint is interchangeable.
## Authentication and errors
For server-to-server API access, use a workspace service token from the user's secret environment. If one is needed, direct the user to Workspace Settings → Service Tokens in Console and have them store it locally or in their secret manager. Use the bearer token without logging it. For an integration acting on behalf of users, use OAuth instead; see [operations](operations.md).
| Failure | Response |
| ------------------------------------ | ---------------------------------------------------------------------------------------- |
| Authentication or permission denied | Explain which authentication or access is missing. |
| Resource not found | Verify the resource ID and workspace; do not create a replacement automatically. |
| Invalid request | Check the current schema and selected region. |
| Rate limit or transient read failure | Retry with bounded backoff, honoring retry guidance. |
| Quota exhausted | Report the limit and available options. |
## Temporary databases with create-db
Use `create-db` when the user needs a working database now and has no connection or Prisma account. By default, the database is available for **24 hours** and is automatically deleted if unclaimed. Claim it through the returned claim URL **before its expiry** to keep it; claiming requires a Prisma account. Use the returned expiry as the deadline if a different lifetime was selected. See the [documented lifecycle](https://www.prisma.io/docs/postgres/npx-create-db#claiming-your-database).
Inspect the current commands when selecting a region or a non-default lifetime:
```bash
npx create-db@latest create --help
npx create-db@latest regions --help
```
Choose a supported region and lifetime. Store the connection string and claim URL privately, then tell the user when the database expires and how to claim it using the returned lifecycle information. Do not promise persistence until claiming is complete. Avoid flags that print credentials into shared output.
For programmatic provisioning, the `create-db` package exposes `create()` and `regions()`. Check the installed types, handle success and error results, and store returned connection/claim information without logging it. See the [create-db documentation](https://www.prisma.io/docs/postgres/npx-create-db).
@@ -0,0 +1,84 @@
# v0, Vercel CLI and Vercel Marketplace
Use the Prisma Postgres native integration so the database belongs to the user's Vercel team, is billed through Vercel, and is connected to the Vercel project. Unless the user asks for a database outside Vercel, do not substitute Prisma Console, the Prisma CLI, `create-db` or a Prisma MCP server: they create a database that Vercel does not bill, connect or rotate.
The integration slug is `prisma` and the product is `prisma/prisma-postgres`.
## 1. Reuse an existing resource
1. In the linked project, run `vercel integration list`. If a Prisma Postgres resource is connected, reuse it and go to step 3.
2. Run `vercel integration list --all` to see the team's resources that are not connected to this project. Connect one with `vercel integration resource connect <resource-name>`.
3. If several resources fit, ask the user which one to use.
## 2. Install and provision with the Vercel CLI
The project must be linked (`vercel link`). Read the current options before provisioning; do not guess metadata or plan IDs:
```bash
vercel integration add prisma --help
vercel integration add prisma/prisma-postgres --name <resource-name>
```
- In a non-interactive shell, pass the `region` metadata (`-m region=<value>`, values from `--help`) and `--plan`. The plan IDs are `free`, `starter`, `pro` and `business`. Use `free` unless the user chose a paid plan: a paid plan bills the user's Vercel account, so ask first.
- If Prisma is not yet installed on the team, the CLI asks the user to accept the integration's terms in the browser and waits. An agent cannot complete this step. Ask the user to accept, then let the command continue.
- By default the command connects the resource to the linked project's `production`, `preview` and `development` environments, then runs `vercel env pull`, which writes `.env.local`.
- One resource on all three environments means local development, previews and production share one database. Tell the user. If they want separate data, provision one resource per environment with `-e <environment>`, and connect only one Prisma resource to each environment.
In v0, use the host's native integration flow instead. It may appear as an integration request tool; discover what the host exposes instead of assuming a fixed tool name, then wait for the connection and its environment variables.
## 3. Environment variables
Connecting a resource sets these variables on each connected environment:
| Variable | Value | Use |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------ |
| `DATABASE_URL` | `postgres://<user>:<key>@db.prisma.io:5432/postgres?sslmode=require` | The application and Prisma CLI commands |
| `POSTGRES_URL` | The same value as `DATABASE_URL` | Libraries that read `POSTGRES_URL` |
| `PRISMA_DATABASE_URL` | The same value on resources created now. On older resources it can be a `prisma+postgres://accelerate.prisma-data.net/...` URL | Do not use in new code; use `DATABASE_URL` |
- With `--prefix`, each name gets the prefix as-is (`--prefix DB2_` gives `DB2_DATABASE_URL`). Read the prefixed name.
- Never print the values. `vercel env ls <environment>` lists names without values.
- `db.prisma.io` is the direct endpoint. It works for the application, migrations and Prisma Studio, so setup needs nothing else. Direct connections are capped low: 10 on Free and Starter, 5 of them reserved for the platform. Before production load from Vercel Functions, tell the user that application traffic should use the pooled endpoint (`pooled.db.prisma.io`), whose connection string Prisma Console shows for the database; `vercel integration open prisma` signs the user in. Do not overwrite the integration's variables: add the pooled string under a new name with `vercel env add`, keep `DATABASE_URL` for migrations, and switch the runtime client only if the user agrees.
## 4. First successful request
1. Make the variables available locally: `vercel env pull`, or run each command with `vercel env run -- <command>` to keep secrets off disk.
2. Return to `prisma-postgres-setup` step 4 to configure the chosen ORM or driver. Prisma ORM configuration belongs to `prisma-orm-setup`.
3. Run one read-only query (for example `SELECT 1`) through the application's ORM or driver against the connected database.
4. Deploy. Environment variable changes apply only to new deployments, so redeploy after connecting a resource, then call a route that queries the database.
## 5. Validate and report
- `vercel integration list` shows the resource, its status and the connected project.
- `vercel env ls production` lists `DATABASE_URL`.
- The local query and the deployed query both succeed.
Report the resource name, the environments it is connected to, the variable the application reads, and the query result, without secrets. If a step was blocked or not tested, say so.
## Plans, billing and backups
- Usage and invoices are on the user's Vercel bill. Changing the plan is the user's decision; do not do it on your own.
- The user can change plans in Prisma Console (`vercel integration open prisma`) or in the Vercel dashboard: **Integrations → Prisma → Manage → Settings → Change Plan**.
- Restorable daily backups come with paid plans. On Free, treat the connected database as having no backup.
## Common errors
| What you see | Cause | Fix |
| ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The CLI asks the user to review and accept terms in the browser | Prisma is not installed on the team yet | Ask the user to accept. The agent cannot do it. |
| Connecting fails with an error that names an existing variable, project and environments | The project already has a variable such as `DATABASE_URL` | Ask the user. Remove the stale variable with `vercel env rm <name> <environment>`, or connect with `--prefix` and read the prefixed name. |
| A Prisma CLI command reports `DATABASE_URL` missing, but the app runs | The command does not load `.env.local` | Run it as `vercel env run -- <command>`, or load the intended file for that command. Do not provision another database. |
| `PRISMA_DATABASE_URL` starts with `prisma+postgres://accelerate.prisma-data.net` | An older resource still carries an Accelerate URL in that variable | Read `DATABASE_URL`, which holds a standard `postgres://` string. |
| Works locally; the deployment has no `DATABASE_URL` or old credentials | The deployment predates the connection or a secret rotation | Check `vercel env ls <environment>` and that the resource is connected to that environment, then redeploy. |
| "Too many connections" or connection-limit errors under load | Application traffic on the direct endpoint, or a client created per request | Create the database client once, outside the request handler. Move application traffic to the pooled endpoint (section 3). |
| Data is gone after a schema diff or reset | A shadow database or reset command ran against the connected database | Never point a shadow database URL or a reset command at the connected database; use a separate throwaway database. Restoring needs a paid plan's backup. |
## Where MCP fits
When native Marketplace MCP tools are available, inspect their descriptions, permissions, and resource scope before use. Use them for supported operations on the selected resource. Keep schema changes consistent with the application's migration workflow.
A general Prisma MCP provisioning tool creates a Prisma resource; that alone does not establish Marketplace registration, billing, project connection, or environment injection. Do not substitute it for a blocked native installation. Report the missing connection or permission.
The agent calls MCP tools while building the app. The generated app connects through its ORM or database driver; it does not need to call MCP for normal database queries.
Sources: [vercel integration](https://vercel.com/docs/cli/integration), [vercel env](https://vercel.com/docs/cli/env), [coding agents and Marketplace integrations](https://vercel.com/kb/guide/using-coding-agents-to-procure-vercel-marketplace-integrations), [Prisma Postgres on Vercel](https://www.prisma.io/docs/guides/postgres/vercel), [connection pooling](https://www.prisma.io/docs/postgres/database/connection-pooling), [v0 databases](https://v0.app/docs/databases), [v0 MCP](https://v0.app/docs/MCP), [Vercel native integrations](https://vercel.com/docs/integrations/create-integration/native-integration).
@@ -0,0 +1,14 @@
---
name: prisma-postgres
description: Deprecated compatibility name for prisma-postgres-setup. Use only when a user or existing integration explicitly invokes prisma-postgres; otherwise select prisma-postgres-setup.
license: MIT
metadata:
author: prisma
version: "8.0.0"
---
# Deprecated: prisma-postgres
Load `prisma-postgres-setup` with the host's skill loader or read its installed `SKILL.md`. If unavailable, install it from [prisma/skills](https://github.com/prisma/skills/tree/main/prisma-postgres-setup) before continuing.
This compatibility entry contains no setup recipes. Keep it until consumers have migrated to the replacement.
@@ -0,0 +1,259 @@
---
name: prisma-upgrade-v7
description: Complete migration guide from Prisma ORM v6 to v7 covering all breaking changes. Use when upgrading Prisma versions, encountering v7 errors, or migrating existing projects. Triggers on "upgrade to prisma 7", "prisma 7 migration", "prisma-client generator", "driver adapter required".
license: MIT
metadata:
author: prisma
version: "7.6.0"
---
# Upgrade to Prisma ORM 7
Complete guide for migrating from Prisma ORM v6 to v7. This upgrade introduces significant breaking changes around the new `prisma-client` generator, driver adapters, `prisma.config.ts`, explicit environment loading, and generated client entrypoints.
## When to Apply
Reference this skill when:
- Upgrading from Prisma v6 to v7
- Updating to the `prisma-client` generator
- Setting up driver adapters
- Configuring `prisma.config.ts`
- Fixing import errors after upgrade
## Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | Schema Migration | CRITICAL | `schema-changes` |
| 2 | Database Connectivity | CRITICAL | `driver-adapters` |
| 3 | Module System | CRITICAL | `esm-support` |
| 4 | Config and Env | HIGH | `prisma-config`, `env-variables` |
| 5 | Removed Features | HIGH | `removed-features` |
| 6 | Accelerate | HIGH | `accelerate-users` |
## Quick Reference
- `schema-changes` - generator migration, required output paths, generated entrypoints, and `Prisma.validator` replacement
- `driver-adapters` - required adapter installation for SQL providers, pool differences, and Prisma Postgres adapter choices
- `esm-support` - ESM-first setup plus CommonJS fallback with `moduleFormat = "cjs"`
- `prisma-config` - creating and using `prisma.config.ts`
- `env-variables` - explicit environment loading
- `removed-features` - removed middleware, metrics, and legacy CLI behavior
- `accelerate-users` - migration notes for Accelerate users
## Using MongoDB? This guide does not apply
Prisma 7 has no MongoDB connector. Do not apply any step in this guide to a project with
`provider = "mongodb"` — see the `prisma-mongodb-upgrade` skill for the actual decision
(stay on v6 deliberately vs migrate to Prisma 8).
## Important Notes
- **MongoDB projects should stay on Prisma 6.x or migrate to Prisma 8** - do not migrate MongoDB apps to Prisma 7's SQL client path (see `prisma-mongodb-upgrade`)
- **Node.js 20.19.0+** required
- **TypeScript 5.4.0+** required
- **Latest stable Prisma ORM version**: `7.6.0`
## Upgrade Steps Overview
1. Update packages to v7
2. Choose your module format (`esm` by default, `cjs` if needed)
3. Update TypeScript configuration
4. Update the schema generator block
5. Create `prisma.config.ts`
6. Install and configure a driver adapter for SQL providers
7. Update Prisma Client imports
8. Update client instantiation
9. Replace deprecated helper patterns like `Prisma.validator`
10. Run `prisma generate` and test
## Quick Upgrade Commands
```bash
# Update packages
npm install @prisma/client@7
npm install -D prisma@7
# Install a driver adapter (PostgreSQL or Prisma Postgres via direct TCP)
npm install @prisma/adapter-pg pg
# Install dotenv for env loading
npm install dotenv
# Regenerate client
npx prisma generate
```
## Breaking Changes Summary
| Change | v6 | v7 |
|--------|----|----|
| Module format | Implicit / mixed | ESM-first, `moduleFormat = "cjs"` supported |
| Generator provider | `prisma-client-js` | `prisma-client` is the default, while `prisma-client-js` still exists for legacy setups |
| Output path | Auto (node_modules) | Required explicit |
| Driver adapters | Optional | Required for SQL providers |
| Config file | `.env` + schema | `prisma.config.ts` |
| Env loading | Automatic | Manual (dotenv) |
| Generated entrypoints | Single package export | `client`, `browser`, `models`, `enums` entrypoints |
| Type-safe query fragments | `Prisma.validator()` | TypeScript `satisfies` |
| Middleware | `$use()` | Client Extensions |
| Metrics | Preview feature | Removed |
## Rule Files
Detailed migration guides for each breaking change:
```
references/esm-support.md - ESM and CommonJS configuration
references/schema-changes.md - Generator, output, imports, and generated entrypoints
references/driver-adapters.md - Required driver adapter setup
references/prisma-config.md - New configuration file
references/env-variables.md - Environment variable loading
references/removed-features.md - Middleware, metrics, and CLI flags
references/accelerate-users.md - Special handling for Accelerate
```
## Step-by-Step Migration
### 1. Update package.json for ESM-first projects
```json
{
"type": "module"
}
```
If you need to stay on CommonJS, keep your app as CJS and set `moduleFormat = "cjs"` in the generator block instead of forcing ESM.
### 2. Update tsconfig.json
```json
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "bundler",
"target": "ES2023",
"strict": true,
"esModuleInterop": true
}
}
```
### 3. Update schema.prisma
```prisma
// Before (v6)
generator client {
provider = "prisma-client-js"
}
// After (v7)
generator client {
provider = "prisma-client"
output = "../generated/prisma"
// Optional if you need CommonJS:
// moduleFormat = "cjs"
}
```
### 4. Create prisma.config.ts
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
datasource: {
url: env('DATABASE_URL'),
},
})
```
### 5. Install a driver adapter (SQL providers only)
```bash
# PostgreSQL
npm install @prisma/adapter-pg pg
# MySQL
npm install @prisma/adapter-mariadb mariadb
# SQLite
npm install @prisma/adapter-better-sqlite3 better-sqlite3
# Prisma Postgres in standard Node.js apps (recommended)
npm install @prisma/adapter-pg pg
# Prisma Postgres serverless driver (edge/serverless)
npm install @prisma/adapter-ppg @prisma/ppg
# Neon
npm install @prisma/adapter-neon
```
MongoDB does not have a SQL `@prisma/adapter-*` package in the published Prisma 7.6.0 packages. If you're upgrading a MongoDB project, stop and keep that project on the latest Prisma 6.x release instead of following the standard Prisma 7 migration path.
### 6. Update client instantiation
```typescript
// Before (v6)
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
// After (v7)
import { PrismaClient } from '../generated/prisma/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL
})
const prisma = new PrismaClient({ adapter })
```
### 7. Replace Prisma.validator with satisfies
```typescript
import { Prisma } from '../generated/prisma/client'
const userSelect = {
id: true,
email: true,
name: true,
} satisfies Prisma.UserSelect
```
### 8. Run migrations and generate
```bash
npx prisma generate
npx prisma migrate dev # if needed
```
## Troubleshooting
### "Cannot find module" errors
- Check that the generator `output` path matches your import path
- Ensure `prisma generate` ran successfully
### SSL certificate errors
- Add `ssl: { rejectUnauthorized: false }` to the adapter config if you need to preserve old behavior
- Or configure your certificates properly with `NODE_EXTRA_CA_CERTS` / OpenSSL CA settings
### Connection timeout issues
- Driver adapters use the underlying driver's defaults, which differ from v6
- Configure pool settings explicitly on the adapter if needed
## Resources
- [Official v7 Upgrade Guide](https://www.prisma.io/docs/orm/more/upgrades/to-v7)
- [Driver Adapters Documentation](https://www.prisma.io/docs/orm/core-concepts/supported-databases/database-drivers)
- [Prisma Config Reference](https://www.prisma.io/docs/orm/reference/prisma-config-reference)
## How to Use
Follow `references/schema-changes.md` and `references/driver-adapters.md` first, then apply the remaining reference files based on your project setup.
@@ -0,0 +1,151 @@
# Prisma Accelerate Users
Special migration instructions for users of Prisma Accelerate or Prisma Postgres with `prisma://` or `prisma+postgres://` URLs.
## Important
**Do NOT pass Accelerate URLs to driver adapters.**
Driver adapters (like `PrismaPg`) expect direct database connection strings. They will fail with `prisma://` or `prisma+postgres://` URLs.
## Correct v7 Setup for Accelerate
### 1. Keep your Accelerate URL
```env
# .env
DATABASE_URL="prisma://accelerate.prisma-data.net/?api_key=..."
# or
DATABASE_URL="prisma+postgres://accelerate.prisma-data.net/..."
```
### 2. Install Accelerate extension
```bash
npm install @prisma/extension-accelerate
```
### 3. Configure prisma.config.ts
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: env('DATABASE_URL'), // Accelerate URL works here
},
})
```
### 4. Instantiate client with accelerateUrl
```typescript
import { PrismaClient } from '../generated/client'
import { withAccelerate } from '@prisma/extension-accelerate'
// Use accelerateUrl instead of adapter
export const prisma = new PrismaClient({
accelerateUrl: process.env.DATABASE_URL,
}).$extends(withAccelerate())
```
## What NOT to Do
```typescript
// ❌ WRONG - Don't use adapter with Accelerate URL
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL // This will fail with prisma://
})
```
## Migrations with Accelerate
For migrations, you may need a direct database connection:
### Option 1: Use Accelerate URL for everything
Accelerate URLs work with Prisma CLI commands:
```bash
# Works with Accelerate URL
prisma migrate deploy
prisma db push
```
### Option 2: Use direct URL for migrations
```env
DATABASE_URL="prisma+postgres://..." # For app
DIRECT_DATABASE_URL="postgresql://..." # For migrations
```
```typescript
// prisma.config.ts
export default defineConfig({
datasource: {
url: env('DIRECT_DATABASE_URL'), // Direct URL for CLI
},
})
```
## Prisma Postgres (Cloud)
If using Prisma Postgres cloud database:
### Same approach
```typescript
import { PrismaClient } from '../generated/client'
import { withAccelerate } from '@prisma/extension-accelerate'
export const prisma = new PrismaClient({
accelerateUrl: process.env.DATABASE_URL, // prisma+postgres:// URL
}).$extends(withAccelerate())
```
## Switching Away from Accelerate
If you later switch to direct TCP connection:
```typescript
// Change from accelerateUrl to adapter
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL // Direct postgres:// URL
})
export const prisma = new PrismaClient({ adapter })
```
## Caching with Accelerate
The extension enables caching:
```typescript
const users = await prisma.user.findMany({
cacheStrategy: {
ttl: 60, // Cache for 60 seconds
swr: 120, // Stale-while-revalidate for 120 seconds
},
})
```
## Edge Runtime
Accelerate works great in edge runtimes:
```typescript
// Works in Vercel Edge, Cloudflare Workers, etc.
import { PrismaClient } from '../generated/client'
import { withAccelerate } from '@prisma/extension-accelerate'
export const prisma = new PrismaClient({
accelerateUrl: process.env.DATABASE_URL,
}).$extends(withAccelerate())
```
@@ -0,0 +1,267 @@
# Driver Adapters
These examples apply to **Prisma ORM 7 SQL clients** during a 6-to-7 upgrade. They do not configure Prisma 8; use the installed package-owned `prisma-8` runtime guidance for that version.
MongoDB should not follow this path. There is no published MongoDB `@prisma/adapter-*` package, and MongoDB projects should remain on the latest Prisma 6.x release instead of trying to fit into the Prisma 7 SQL adapter model.
## Why Driver Adapters?
- No native engine binary in the Prisma Client SQL path
- Smaller bundle size
- Better serverless/edge compatibility
- Uses native Node.js database drivers
- More control over connection pooling
## Available Adapters
| Database | Adapter Package | Underlying Driver |
|----------|-----------------|-------------------|
| PostgreSQL | `@prisma/adapter-pg` | `pg` |
| MySQL / MariaDB | `@prisma/adapter-mariadb` | `mariadb` |
| SQLite | `@prisma/adapter-better-sqlite3` | `better-sqlite3` |
| Prisma Postgres (Node.js) | `@prisma/adapter-pg` | `pg` |
| Prisma Postgres (edge/serverless) | `@prisma/adapter-ppg` | `@prisma/ppg` |
| SQL Server | `@prisma/adapter-mssql` | `mssql` |
| Neon | `@prisma/adapter-neon` | `@neondatabase/serverless` |
| PlanetScale | `@prisma/adapter-planetscale` | `@planetscale/database` |
| Turso/libSQL | `@prisma/adapter-libsql` | `@libsql/client` |
| D1 (Cloudflare) | `@prisma/adapter-d1` | Cloudflare D1 |
## Installation
### PostgreSQL
```bash
npm install @prisma/adapter-pg
```
### MySQL
```bash
npm install @prisma/adapter-mariadb mariadb
```
### SQLite
```bash
npm install @prisma/adapter-better-sqlite3
```
### Prisma Postgres
```bash
npm install @prisma/adapter-pg pg
```
### SQL Server
```bash
npm install @prisma/adapter-mssql mssql
```
## Configuration
### PostgreSQL
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL
})
const prisma = new PrismaClient({ adapter })
```
### MySQL
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaMariaDb } from '@prisma/adapter-mariadb'
const adapter = new PrismaMariaDb({
host: 'localhost',
port: 3306,
connectionLimit: 5,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
})
const prisma = new PrismaClient({ adapter })
```
### SQLite
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3'
const adapter = new PrismaBetterSqlite3({
url: process.env.DATABASE_URL || 'file:./dev.db'
})
const prisma = new PrismaClient({ adapter })
```
### Neon (Serverless PostgreSQL)
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaNeon } from '@prisma/adapter-neon'
const adapter = new PrismaNeon({
connectionString: process.env.DATABASE_URL
})
const prisma = new PrismaClient({ adapter })
```
### Prisma Postgres
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL,
})
const prisma = new PrismaClient({ adapter })
```
### Prisma Postgres serverless driver
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaPostgresAdapter } from '@prisma/adapter-ppg'
const prisma = new PrismaClient({
adapter: new PrismaPostgresAdapter({
connectionString: process.env.PRISMA_DIRECT_TCP_URL,
}),
})
```
### SQL Server
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaMssql } from '@prisma/adapter-mssql'
const adapter = new PrismaMssql({
server: 'localhost',
port: 1433,
database: 'mydb',
user: process.env.SQLSERVER_USER,
password: process.env.SQLSERVER_PASSWORD,
options: {
encrypt: true,
trustServerCertificate: true,
},
})
const prisma = new PrismaClient({ adapter })
```
## Connection Pool Configuration
Driver adapters use the underlying driver's pool settings, which differ from v6 defaults.
### PostgreSQL with custom pool
```typescript
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL,
// Pool configuration
max: 10, // Maximum connections
idleTimeoutMillis: 30000, // Close idle connections after 30s
connectionTimeoutMillis: 5000, // Connection timeout (v6 default was 5s)
})
```
### Matching v6 behavior
```typescript
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL,
connectionTimeoutMillis: 5000, // v6 used 5 second timeout
})
```
## SSL Configuration
### Accept self-signed certificates
```typescript
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false // Accept self-signed certs
}
})
```
### Proper SSL configuration
```typescript
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL,
ssl: {
ca: fs.readFileSync('/path/to/ca-cert.pem'),
rejectUnauthorized: true
}
})
```
## Migration from v6
### Before (v6)
```typescript
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient({
datasources: {
db: { url: process.env.DATABASE_URL }
}
})
```
### After (v7)
```typescript
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL
})
const prisma = new PrismaClient({ adapter })
```
## Singleton Pattern
```typescript
// lib/prisma.ts
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined
}
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL!
})
export const prisma = globalForPrisma.prisma ?? new PrismaClient({ adapter })
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma
}
```
@@ -0,0 +1,161 @@
# Environment Variables
Prisma v7 no longer automatically loads environment variables. You must load them explicitly.
## The Change
### v6 Behavior
Prisma CLI automatically loaded `.env` files.
### v7 Behavior
You must manually load environment variables using `dotenv` or similar.
## Setup
### 1. Install dotenv
```bash
npm install dotenv
```
### 2. Import in prisma.config.ts
```typescript
import 'dotenv/config' // Must be first import
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
datasource: {
url: env('DATABASE_URL'),
},
})
```
## Bun Users
Bun automatically loads `.env` files. No additional setup needed:
```typescript
// prisma.config.ts (Bun)
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
datasource: {
url: env('DATABASE_URL'),
},
})
```
## Multiple .env Files
### Using dotenv-cli
```bash
npm install -D dotenv-cli
```
```json
{
"scripts": {
"db:migrate": "dotenv -e .env.local -- prisma migrate dev",
"db:push": "dotenv -e .env.development -- prisma db push"
}
}
```
### Using dotenv with path
```typescript
// prisma.config.ts
import { config } from 'dotenv'
import path from 'path'
// Load specific .env file
config({ path: path.join(__dirname, '.env.local') })
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
datasource: {
url: env('DATABASE_URL'),
},
})
```
## Application Code
For your application, load env vars at startup:
### Entry point
```typescript
// index.ts
import 'dotenv/config'
import { PrismaClient } from '../generated/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL!
})
const prisma = new PrismaClient({ adapter })
```
### Or use dotenv explicitly
```typescript
import { config } from 'dotenv'
config()
// Now process.env.DATABASE_URL is available
```
## Removed Environment Variables
These Prisma-specific env vars are removed in v7:
| Removed Variable | Alternative |
|-----------------|-------------|
| `PRISMA_CLI_QUERY_ENGINE_TYPE` | Not needed (no engines) |
| `PRISMA_CLIENT_ENGINE_TYPE` | Not needed (no engines) |
| `PRISMA_QUERY_ENGINE_BINARY` | Not needed |
| `PRISMA_QUERY_ENGINE_LIBRARY` | Not needed |
| `PRISMA_GENERATE_SKIP_AUTOINSTALL` | Not needed |
| `PRISMA_SKIP_POSTINSTALL_GENERATE` | Not needed |
| `PRISMA_GENERATE_IN_POSTINSTALL` | Not needed |
| `PRISMA_GENERATE_DATAPROXY` | Migrate to `prisma-client` with driver adapters |
| `PRISMA_GENERATE_NO_ENGINE` | Migrate to `prisma-client` with driver adapters |
| `PRISMA_CLIENT_NO_RETRY` | Configure on adapter |
| `PRISMA_MIGRATE_SKIP_GENERATE` | Not needed (auto-generate removed) |
| `PRISMA_MIGRATE_SKIP_SEED` | Not needed (auto-seed removed) |
## TypeScript env() Helper
The `env()` function from `prisma/config` provides type safety:
```typescript
import { env } from 'prisma/config'
// Type-safe environment variable access
const url = env('DATABASE_URL') // string
```
Note: This only works within `prisma.config.ts`, not in your application code.
## CI/CD Considerations
Ensure environment variables are set in your CI environment:
```yaml
# GitHub Actions
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
steps:
- run: npx prisma migrate deploy
```
No need for dotenv in CI if variables are set directly.
@@ -0,0 +1,128 @@
# ESM and CommonJS Support
Prisma ORM v7 is ESM-first, but the `prisma-client` generator can target either ESM or CommonJS. Use ESM by default, and opt into CommonJS with `moduleFormat = "cjs"` if your project still needs it.
## ESM Projects
Add `"type": "module"` to `package.json` and use an ESM-compatible `tsconfig.json`:
```json
{
"type": "module",
"scripts": {
"build": "tsc",
"start": "node dist/index.js"
}
}
```
```json
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "bundler",
"target": "ES2023",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "dist"
},
"include": ["src/**/*", "prisma/**/*"]
}
```
## CommonJS Projects
If the rest of your app is still CommonJS, keep that setup and make the generated Prisma Client CommonJS too:
```json
{
"compilerOptions": {
"module": "CommonJS",
"moduleResolution": "node",
"target": "ES2022",
"esModuleInterop": true
}
}
```
```prisma
generator client {
provider = "prisma-client"
output = "../generated/prisma"
moduleFormat = "cjs"
}
```
## Generator Fields That Matter
- `moduleFormat`: `esm` or `cjs`
- `runtime`: `nodejs`, `bun`, `deno`, `workerd`, `vercel-edge`, `react-native`
- `generatedFileExtension`: `ts`, `mts`, or `cts`
- `importFileExtension`: `ts`, `mts`, `cts`, `js`, `mjs`, `cjs`, or empty
Example:
```prisma
generator client {
provider = "prisma-client"
output = "../generated/prisma"
runtime = "nodejs"
moduleFormat = "esm"
generatedFileExtension = "ts"
importFileExtension = "ts"
}
```
## Import Paths
### Server Code
```typescript
import { PrismaClient } from '../generated/prisma/client'
```
### Browser-Safe Types
```typescript
import { Prisma } from '../generated/prisma/browser'
import { Role } from '../generated/prisma/enums'
import type { UserModel } from '../generated/prisma/models/User'
```
## File Extensions
With `moduleResolution: "Node16"` or `"NodeNext"`, use `.js`/`.mjs`/`.cjs` extensions that match your emitted files.
With `moduleResolution: "bundler"`, bare relative imports are usually fine.
## Minimum Versions
| Requirement | Minimum Version |
|-------------|-----------------|
| Node.js | 20.19.0 |
| TypeScript | 5.4.0 |
## Framework Considerations
### Next.js
Next.js works well with the default ESM output. If you need generated types in client components, import them from `browser`, `models`, or `enums`, not from `client`.
### Bun
Bun loads `.env` files automatically, so ESM plus `env()` is the smoothest default. You can still choose `moduleFormat = "cjs"` if the rest of your project requires it.
## Troubleshooting
### "ERR_REQUIRE_ESM"
Your generated client is ESM, but your app is requiring it as CommonJS. Either switch the project to ESM or set `moduleFormat = "cjs"` and regenerate.
### "Cannot use import statement outside a module"
Your app is still being executed as CommonJS. Add `"type": "module"` or use `moduleFormat = "cjs"` instead.
### TypeScript compilation errors
Ensure `module`, `moduleResolution`, and your generator's `moduleFormat` agree with one another.
@@ -0,0 +1,203 @@
# Prisma Config
Prisma v7 introduces `prisma.config.ts` as the central configuration file for the Prisma CLI.
## Location
Place `prisma.config.ts` at your project root (next to `package.json`).
## Basic Configuration
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
datasource: {
url: env('DATABASE_URL'),
},
})
```
## Configuration Options
### schema
Path to your Prisma schema file:
```typescript
schema: 'prisma/schema.prisma'
```
### datasource.url
Database connection URL:
```typescript
datasource: {
url: env('DATABASE_URL'),
}
```
### datasource.directUrl
Direct connection URL (bypassing connection pooler):
```typescript
datasource: {
url: env('DATABASE_URL'),
directUrl: env('DIRECT_DATABASE_URL'),
}
```
### datasource.shadowDatabaseUrl
Shadow database for migrations:
```typescript
datasource: {
url: env('DATABASE_URL'),
shadowDatabaseUrl: env('SHADOW_DATABASE_URL'),
}
```
### migrations.path
Directory for migration files:
```typescript
migrations: {
path: 'prisma/migrations',
}
```
### migrations.seed
Seed command for `prisma db seed`:
```typescript
migrations: {
path: 'prisma/migrations',
seed: 'tsx prisma/seed.ts',
}
```
## Full Example
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
// Schema location
schema: 'prisma/schema.prisma',
// Migration configuration
migrations: {
path: 'prisma/migrations',
seed: 'tsx prisma/seed.ts',
},
// Database connection
datasource: {
url: env('DATABASE_URL'),
directUrl: env('DIRECT_DATABASE_URL'),
shadowDatabaseUrl: env('SHADOW_DATABASE_URL'),
},
})
```
## Environment Variables
### The env() helper
Use `env()` to reference environment variables:
```typescript
import { env } from 'prisma/config'
datasource: {
url: env('DATABASE_URL'),
}
```
This provides type safety but does NOT load .env files automatically.
### Loading .env files
Install and import dotenv:
```bash
npm install dotenv
```
```typescript
import 'dotenv/config' // Must be first import
import { defineConfig, env } from 'prisma/config'
```
## Migrating from v6
### Before (v6) - schema.prisma
```prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}
```
### After (v7) - prisma.config.ts
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: env('DATABASE_URL'),
directUrl: env('DIRECT_URL'),
},
})
```
And update schema.prisma:
```prisma
datasource db {
provider = "postgresql"
// URLs now in prisma.config.ts
}
```
## Custom Config Path
Use `--config` flag with CLI commands:
```bash
prisma migrate dev --config ./config/prisma.config.ts
```
## Monorepo Configuration
```typescript
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'
import path from 'path'
export default defineConfig({
schema: path.join(__dirname, 'packages/database/prisma/schema.prisma'),
migrations: {
path: path.join(__dirname, 'packages/database/prisma/migrations'),
},
datasource: {
url: env('DATABASE_URL'),
},
})
```
@@ -0,0 +1,230 @@
# Removed Features
Several features have been removed in Prisma v7. Here's how to migrate.
## Client Middleware
### Removed
```typescript
// ❌ No longer works in v7
prisma.$use(async (params, next) => {
const before = Date.now()
const result = await next(params)
const after = Date.now()
console.log(`Query took ${after - before}ms`)
return result
})
```
### Use Client Extensions Instead
```typescript
// ✅ v7 approach
const prisma = new PrismaClient({ adapter }).$extends({
query: {
$allModels: {
async $allOperations({ operation, model, args, query }) {
const before = Date.now()
const result = await query(args)
const after = Date.now()
console.log(`${model}.${operation} took ${after - before}ms`)
return result
},
},
},
})
```
### Common Middleware Patterns
#### Soft delete
```typescript
const prisma = new PrismaClient({ adapter }).$extends({
query: {
user: {
async delete({ args, query }) {
// Convert delete to soft delete
return prisma.user.update({
where: args.where,
data: { deletedAt: new Date() },
})
},
async findMany({ args, query }) {
// Filter out soft-deleted records
args.where = { ...args.where, deletedAt: null }
return query(args)
},
},
},
})
```
#### Logging
```typescript
const prisma = new PrismaClient({ adapter }).$extends({
query: {
$allModels: {
async $allOperations({ operation, model, args, query }) {
console.log(`${model}.${operation}`, JSON.stringify(args))
return query(args)
},
},
},
})
```
## Metrics
### Removed
The Metrics preview feature has been removed.
```typescript
// ❌ No longer works
const metrics = await prisma.$metrics.json()
```
### Alternatives
#### Custom counter with extensions
```typescript
let totalQueries = 0
const prisma = new PrismaClient({ adapter }).$extends({
client: {
async $totalQueries() {
return totalQueries
},
},
query: {
$allModels: {
async $allOperations({ query, args }) {
totalQueries += 1
return query(args)
},
},
},
})
// Usage
const count = await prisma.$totalQueries()
```
#### Use driver-level metrics
Access metrics from the underlying driver adapter.
## CLI Flags Removed
### --skip-generate
Removed from `migrate dev` and `db push`.
```bash
# v6
prisma migrate dev --skip-generate
# v7 - generate is not run automatically
prisma migrate dev
prisma generate # Run explicitly if needed
```
Local verification with Prisma `7.6.0` showed no generated client files emitted by `migrate dev` or `db push`, even though some CLI help text still says `migrate dev` "trigger[s] generators".
### --skip-seed
Removed from `migrate dev`. More importantly, Prisma v7 no longer auto-runs seeds during `migrate dev` or `migrate reset`, so seed explicitly when you need it.
```bash
# v6
prisma migrate dev --skip-seed
# v7 - seed is not run automatically
prisma migrate dev
prisma db seed # Run explicitly if needed
```
### --schema and --url from db execute
```bash
# v6
prisma db execute --file ./script.sql --url "$DATABASE_URL"
# v7 - configure in prisma.config.ts
prisma db execute --file ./script.sql
```
## migrate diff Options
| Removed | Replacement |
|---------|-------------|
| `--from-url` | `--from-config-datasource` |
| `--to-url` | `--to-config-datasource` |
| `--from-schema-datasource` | `--from-config-datasource` |
| `--to-schema-datasource` | `--to-config-datasource` |
| `--shadow-database-url` | Configure in `prisma.config.ts` |
### Example
```bash
# v6
prisma migrate diff --from-url "$DATABASE_URL" --to-schema schema.prisma
# v7
prisma migrate diff --from-config-datasource --to-schema schema.prisma
```
## Automatic Behaviors Removed
### Auto-generate after migrate
```bash
# v7 workflow
prisma migrate dev --name add_field
prisma generate # Must run explicitly
```
### Auto-seed after migrate
```bash
# v7 workflow
prisma migrate reset --force
prisma db seed # Must run explicitly
```
## Prisma.validator
The `prisma-client` generator no longer exposes `Prisma.validator`. Use TypeScript's `satisfies` operator instead.
```typescript
import { Prisma } from '../generated/prisma/client'
const userSelect = {
id: true,
email: true,
} satisfies Prisma.UserSelect
```
## rejectOnNotFound
Removed in v5.0.0 (already deprecated).
```typescript
// ❌ Removed
const prisma = new PrismaClient({
rejectOnNotFound: true,
})
// ✅ Use OrThrow methods
const user = await prisma.user.findUniqueOrThrow({
where: { id: 1 },
})
const user = await prisma.user.findFirstOrThrow({
where: { email: 'test@example.com' },
})
```
@@ -0,0 +1,164 @@
# Schema Changes
Prisma v7 promotes `prisma-client` to the default generator. Update your generator block, output path, and imports accordingly.
This guide is for projects that are actually migrating to Prisma 7. Do not apply these schema changes to MongoDB projects; keep those on Prisma 6.x.
## Generator Block (v7)
```prisma
generator client {
provider = "prisma-client"
output = "../generated/prisma"
}
```
## Key Changes
### 1. Provider name
Use `prisma-client` in Prisma v7. The older `prisma-client-js` generator still exists in the repo for legacy setups, but `prisma-client` is the default path for current projects.
### 2. Output is required
The `output` field is mandatory when using `prisma-client`. Prisma Client no longer generates to `node_modules` with this generator.
```prisma
generator client {
provider = "prisma-client"
output = "../generated/prisma"
}
```
### 3. engineType changed
Legacy Rust engine settings are gone. With `prisma-client`, the relevant value is `engineType = "client"` if you want to state it explicitly, although it is typically inferred and can be omitted.
```prisma
generator client {
provider = "prisma-client"
output = "../generated/prisma"
engineType = "client"
}
```
### 4. moduleFormat is explicit when needed
If you must stay on CommonJS:
```prisma
generator client {
provider = "prisma-client"
output = "../generated/prisma"
moduleFormat = "cjs"
}
```
## Example Output Paths
### Standard project
```prisma
output = "../generated/prisma"
```
Creates files like:
```text
generated/prisma/
client.ts
browser.ts
enums.ts
models.ts
models/
```
### Monorepo
```prisma
output = "../../packages/database/generated/prisma"
```
### Same directory as schema
```prisma
output = "./generated/prisma"
```
Creates: `prisma/generated/prisma/client.ts`
## Datasource Block
The `url`, `directUrl`, and `shadowDatabaseUrl` fields in the `datasource` block are deprecated in Prisma v7. Move them to `prisma.config.ts` and keep only the provider in `schema.prisma`:
```prisma
datasource db {
provider = "postgresql"
}
```
```typescript
export default defineConfig({
datasource: {
url: env('DATABASE_URL'),
directUrl: env('DIRECT_URL'),
shadowDatabaseUrl: env('SHADOW_DATABASE_URL'),
},
})
```
## After Schema Changes
1. Run `prisma generate`:
```bash
npx prisma generate
```
2. Update imports throughout your codebase:
```typescript
import { PrismaClient } from '../generated/prisma/client'
```
3. Update `.gitignore` if you manage this manually:
```
/generated/prisma
```
4. Replace `Prisma.validator()` with TypeScript `satisfies` when using `prisma-client`:
```typescript
import { Prisma } from '../generated/prisma/client'
const userSelect = {
id: true,
email: true,
} satisfies Prisma.UserSelect
```
## Generated Entrypoints
- `client` - server-side Prisma Client and Prisma namespace
- `browser` - browser-safe types and enums without a real `PrismaClient`
- `enums` - slim enum-only entrypoint
- `models` - model types and derived helper types
## Preview Features
Preview features still work as before:
```prisma
generator client {
provider = "prisma-client"
output = "../generated/prisma"
previewFeatures = ["relationJoins", "fullTextSearch"]
}
```
Recent preview-feature examples also include `partialIndexes` for PostgreSQL, SQLite, SQL Server, and CockroachDB:
```prisma
generator client {
provider = "prisma-client"
output = "../generated/prisma"
previewFeatures = ["partialIndexes"]
}
```
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-cli
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-client-api
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-compute
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-database-setup
@@ -0,0 +1 @@
../../.agents/skills/prisma-driver-adapter-implementation
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-mongodb-upgrade
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-orm-setup
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-postgres
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-postgres-setup
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-upgrade-v7
+36 -1
View File
@@ -1,3 +1,38 @@
NODE_ENV=development NODE_ENV=development
HOST=127.0.0.1 HOST=127.0.0.1
PORT=3000 PORT=8800
LOG_LEVEL=info
API_BODY_LIMIT_BYTES=1048576
# 开发默认开启,生产默认关闭;可显式设置 true/false。
SWAGGER_ENABLED=true
# 只允许明确配置的 Web origin;小程序请求无需 CORS origin。
CORS_ORIGINS=
# 仅在部署明确确认 Nginx 来源时设置 IP/CIDR,默认不信任转发头。
TRUSTED_PROXY_CIDRS=
# 必填;至少 32 字节,开发/测试/生产分别生成,不使用共享默认值。
JWT_SECRET=
JWT_ISSUER=doodle-store
JWT_AUDIENCE=doodle-mini
JWT_EXPIRES_IN_SECONDS=86400
# 微信静默登录已接入,两项均必填;小程序 AppID 与对应 AppSecret。
# 仅服务端持有 AppSecret,不提交实际密钥,也不使用 JWT_SECRET 代替。
WECHAT_MINI_APP_ID=
WECHAT_MINI_APP_SECRET=
# Prisma 必填;用户名/密码/端口须与根 .env 一致,密码需 URL 编码。
# 仅连接 public schema;不要提交实际连接凭证。
DATABASE_URL=postgresql://doodle_dev:change-me-local-only@127.0.0.1:5434/doodle_dev?schema=public
# 新品按真实首次发布时间计算;旧数据发布时间未知时不标新品。
WORKSHEET_NEW_WINDOW_DAYS=30
# 可选公共资源 HTTPS 域名(不含路径);只解析 ready/public 资产,不授予上传权限。
QINIU_PUBLIC_DOMAIN=https://cdn.joeyone.cn
# 与 asset-sync 一致;前缀只拼接到备份相对路径,objectKey 本身已经包含前缀。
QINIU_KEY_PREFIX=doodle-assets/
# 对象所属空间,不是 URL 中的路径,也不需要在 server 配置 AK/SK。
QINIU_BUCKET=doodle-cn
# 仅服务端接收用户/管理员上传时使用,不能下发小程序。
QINIU_AK=
QINIU_SK=
QINIU_REGION=
# 首页每日刷新 UTC 小时(默认北京时间 06:00),可由管理员暂停。
SITE_REFRESH_HOUR_UTC=22
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-cli
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-client-api
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-compute
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-database-setup
@@ -0,0 +1 @@
../../.agents/skills/prisma-driver-adapter-implementation
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-mongodb-upgrade
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-orm-setup
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-postgres
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-postgres-setup
+1
View File
@@ -0,0 +1 @@
../../.agents/skills/prisma-upgrade-v7
+7
View File
@@ -0,0 +1,7 @@
| 配置项 | 填写内容 |
| ------ | -------------------------------------------- |
| 主机 | `127.0.0.1` |
| 端口 | `5434` |
| 数据库 | `doodle_dev` |
| 用户名 | `doodle_dev` |
| 密码 | `doodle-store/.env` 中的 `POSTGRES_PASSWORD` |

Some files were not shown because too many files have changed in this diff Show More