運用と注意点
Edge / Serverless 対応、Connection Pool、本番マイグレーション、 パフォーマンス、ロギング、Drizzle との比較まで。
Edge / Serverless で動かす
Vercel(Node ランタイム)
- 標準の
@prisma/clientがそのまま動く - Connection Pool は外部を強く推奨(Accelerate / Supabase / PgBouncer)
connection_limit=1+ 外部 Pool が定石- middleware(Edge Runtime)で使うなら Driver Adapter が必須
Cloudflare Workers / Pages Functions
- Driver Adapter または Accelerate が必須
- D1(SQLite)も
@prisma/adapter-d1で利用可 - バンドルサイズに注意、未使用 model を生成から除外することも検討
AWS Lambda
- cold start の影響を減らすため外部 Poolを立てる
- Lambda 用の
binaryTargets指定("rhel-openssl-3.0.x") - RDS Proxy 経由を推奨
Connection 管理
Serverless でのつまずき
- 関数の同時起動数 × connection_limit 接続数
- Postgres は500 同時接続程度が上限(プランによる)
- 外部 Pool が無いと瞬間的に枯渇
解決策
- Prisma Accelerate: HTTP 経由 + 公式 Pool(推奨)
- Supabase Supavisor / PgBouncer: 自前 Pool
- RDS Proxy: AWS 公式
- Neon Serverless Driver: WebSocket ベース
パフォーマンス Tips
SELECT で必要な列だけ
- 大きな text / json / blob 列を毎回引かない
- select で明示的に絞る
include を浅く
- 3 段以上の include は要注意
- 必要なら別クエリで Promise.all
インデックス
- WHERE / ORDER BY に使う列は必ず
- 1-N の子側 FK 列に必須
- EXPLAIN で確認
クエリの並列化
// 直列(遅い)
const a = await prisma.post.count()
const b = await prisma.user.count()
// 並列
const [a, b] = await Promise.all([
prisma.post.count(),
prisma.user.count(),
])
大量バッチは createMany + chunk
- 1 件ずつループは絶対 NG
- 1000〜5000 ずつまとめる
ホット行は楽観ロック
「views を increment」のような頻出更新は updateMany + where 条件で原子的に。
本番マイグレーション
- 必ずmigrate deploy(dev でない)
- 事前にステージングで実行時間を計測
- 大テーブルへの ALTER は段階的に
- ロックを取らない CONCURRENTLY を使う
- 失敗時のロールバック手順を用意
- schema.prisma と migrations/ をセットでコミット
環境変数と Secret
- 本番の DATABASE_URL は Secret Manager / Vercel Env / GitHub Secrets で管理
- schema.prisma にはハードコードしない
- directUrl が必要なケース(PgBouncer 経由)を忘れない
- local の .env と CI の Secret で同名にしておく
監視・ロギング
- クエリログ → スロークエリ抽出
$metrics.prometheus()→ Grafana 連携- Sentry / Datadog で例外トラッキング(P2002 / P2003 などは異常検知)
- DB 側のスロークエリログも有効化(
log_min_duration_statement)
テスト
テスト DB
- 専用の DB(
app_test)を別途用意 - 各テスト前に
truncateでリセット - Docker で立ち上げる
シードデータ
// test/setup.ts
beforeAll(async () => {
await prisma.$executeRaw`TRUNCATE "Post", "User" RESTART IDENTITY CASCADE`
})
afterAll(async () => {
await prisma.$disconnect()
})
Mock
prisma-mock/jest-mock-extendedで in-memory モック- 本物の DB 統合テストの方が結局信頼できる
セキュリティ
- $queryRawUnsafe は絶対にユーザ入力を直接埋め込まない
- テンプレートリテラル形式で自動エスケープ
- RLS(Postgres / Supabase)と組み合わせるなら、Prisma はanon 権限で接続するパターンも
- 機密列(password_hash 等)は select で明示的に省く(uncovered フィールドの設定)
機密フィールドの隠蔽(v5+)
model User {
id String @id
email String @unique
passwordHash String
}
// $extends で常に exclude
const xprisma = prisma.$extends({
result: {
user: {
passwordHash: { needs: { passwordHash: true }, compute: () => undefined }
}
}
})
Drizzle / Kysely との比較
| Prisma | Drizzle | Kysely | |
|---|---|---|---|
| API | 独自オブジェクト | SQL に近い | SQL に近い |
| スキーマ | 独自 DSL(schema.prisma) | TS で書く | TS で書く |
| マイグレーション | 純正(強力) | drizzle-kit | 外部 |
| 型推論 | 強 | 強 | 強 |
| Edge | Driver Adapter / Accelerate | ネイティブ◎ | ネイティブ◎ |
| バンドルサイズ | 大 | 小 | 小 |
| 得意 | 標準的な OLTP | SQL 制御 | SQL ビルダ |
Prisma を使い続けるか / 捨てるかの判断軸
- 使い続け: 標準的な CRUD 中心、型安全 DX 重視、Postgres 中心
- Drizzle 検討: Cloudflare Workers / Edge ネイティブ、SQL を書きたい、軽量バンドル
- Kysely 検討: SQL ビルダだけ欲しい、ORM 不要
- 大事なのは「マイグレーション資産」。乗り換えるなら計画的に
運用チェックリスト
- ☐ PrismaClient はシングルトン
- ☐ 本番は migrate deploy
- ☐ Connection Pool(外部)を入れた
- ☐ schema と migrations が Git 管理
- ☐ CI で migrate & テスト
- ☐ スロークエリのアラート
- ☐ DB バックアップを別場所にも
- ☐ Edge / Serverless 用の adapter 準備
- ☐ binary targets が CI / 本番ビルド環境に合っている
- ☐ 機密列が select で漏れない仕組み
失敗事例から学ぶ
- HMR で接続爆発 → シングルトンパターン
- Vercel から Postgres に直接 → Pool 枯渇 → Accelerate 導入
- 本番で migrate dev → 事故
- Edge で動かない → Driver Adapter
- 巨大 include で 30 秒 → select 絞る + 並列化
- $queryRawUnsafe + ユーザ入力 → SQL Injection
- NOT NULL 追加で本番停止 → 段階的移行
関連リソース
本セクションの総括
- セットアップ でローカルから始める
- schema.prisma でモデルを宣言
- migrate で履歴管理
- Client で型安全な CRUD
- リレーション と トランザクション を押さえる
- 高度な機能 は必要になってから
- 本ページの運用を守る
最後に
Prisma は「型 + DX」を最大化する ORM。本物の SQL の理解とセットで使うと真価を発揮する。 DB を抽象化するツールではあるが、SQL から逃げるためのツールではない。