← 記事一覧に戻る

Prisma + Vercel で "PrismaClient is not a constructor" / "PrismaClientInitializationError" が出て動かない時の5つの原因と対策【Serverless / Edge Runtime】

はじめに

PrismaをVercelにデプロイしたとき、ローカルでは動くのに本番で以下のようなエラーが出てハマった経験はないでしょうか。

PrismaClient is not a constructor
PrismaClientInitializationError: Unable to require('.../.prisma/client/index.js')
@prisma/client did not initialize yet. Please run "prisma generate" and try to import it again.

これらはPrisma + Vercelの組み合わせで非常によく起きる問題ですが、日本語の情報が少なく解決まで時間がかかりがちです。この記事では原因を5つに絞って解説します。


原因1: prisma generate がビルド時に実行されていない(最多)

Prismaは @prisma/client をインストールするだけでは動きません。prisma generate を実行することで、node_modules/.prisma/client/ にスキーマに対応したクライアントコードが生成されます。

Vercelのビルドはクリーンな環境で実行されるため、ローカルで生成したクライアントファイルは存在しません。postinstallbuild スクリプトに追加していないと、本番ビルドで毎回この問題が発生します。

解決策: postinstall スクリプトに追加する

{
  "scripts": {
    "postinstall": "prisma generate"
  }
}

postinstallnpm install 後に自動で実行されるため、Vercelのビルド時にも prisma generate が走るようになります。

build スクリプトに直接含める方法でも対応できます。

{
  "scripts": {
    "build": "prisma generate && next build"
  }
}

**これだけで多くのケースが解決します。**まず最初にこれを試してください。


原因2: Edge Runtime で PrismaClient が使えない

Next.js App Router の Route Handler や Middleware で runtime = 'edge' を指定している場合、@prisma/client はそのままでは動きません。

// ❌ Edge Runtime では動かない
export const runtime = 'edge'

import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient() // ここでクラッシュ

@prisma/client はNode.jsのネイティブモジュール(fspathnet 等)に依存しているため、V8ベースのEdge Runtimeでは使用できません。エラーメッセージが PrismaClient is not a constructorModule not found になることもあり、原因が分かりにくいです。

解決策1: Edge Runtimeをやめる(最も簡単)

// ✅ runtime 指定を削除するか nodejs に変更
export const runtime = 'nodejs'

DBアクセスが必要なRoute HandlerにEdge Runtimeを使う理由はほぼないため、削除するのが最も安全です。

解決策2: Prisma Accelerate を使う(Edge対応)

Edge Runtimeでも使いたい場合はPrisma Accelerateを導入します。

npm install @prisma/extension-accelerate
import { PrismaClient } from '@prisma/client'
import { withAccelerate } from '@prisma/extension-accelerate'

const prisma = new PrismaClient().$extends(withAccelerate())

Prisma Accelerateはコネクションプーリングも提供するため、Serverless環境全般で有効です。


原因3: Serverless環境でのコネクション枯渇

VercelはServerless Functionをリクエストごとに新しいプロセスで起動します。関数の中で毎回 new PrismaClient() を呼ぶと、リクエストのたびにDBコネクションが増殖して枯渇します。

// ❌ 毎回 new PrismaClient() を生成するとコネクションが枯渇
export async function GET() {
  const prisma = new PrismaClient()
  const users = await prisma.user.findMany()
  await prisma.$disconnect()
  return Response.json(users)
}

エラーは Can't reach database server や接続タイムアウトとして現れることが多く、一見すると原因が「コネクション枯渇」とは気づきにくいです。

解決策: グローバルシングルトンパターン

// lib/prisma.ts
import { PrismaClient } from '@prisma/client'

const globalForPrisma = global as unknown as { prisma: PrismaClient }

export const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    log: "production" === 'development' ? ['query'] : [],
  })

if ("production" !== 'production') globalForPrisma.prisma = prisma

global オブジェクトにインスタンスを保持することで、ホットリロード時に複数インスタンスが生成されるのを防ぎます。

また、接続URLに connection_limit を追加してコネクション数を明示的に制限するのも有効です。

DATABASE_URL="postgresql://user:pass@host/db?connection_limit=5&pool_timeout=10"

PgBouncerなどのコネクションプーラーを使う場合は ?pgbouncer=true も忘れずに。


原因4: 環境変数 DATABASE_URL が設定されていない・反映されていない

Vercelのダッシュボードで環境変数を設定したのに Can't reach database server at '' のようにホスト名が空になるケースがあります。よくある見落としを確認してください。

チェックリスト

  • Vercel ダッシュボード → Settings → Environment VariablesDATABASE_URL が存在するか
  • スコープ(Production / Preview / Development)が適切に設定されているか
  • 設定後にリデプロイを実行したか(環境変数の変更はデプロイ時に読み込まれる)
  • 接続文字列に特殊文字(@#%!等)が含まれていてURLエンコードが必要でないか

特にパスワードに特殊文字が含まれる場合はURLエンコードが必要です。

# パスワードに @ が含まれる場合は %40 にエンコード
DATABASE_URL="postgresql://user:p%40ssword@host:5432/db"
#                                  ^^^
#                             @ → %40

SupabaseやNeon、PlanetScaleなどのクラウドDBを使っている場合は、そのダッシュボードで「接続文字列をコピー」して貼り付けるのが最も確実です。


原因5: モノレポ環境での output ディレクトリのズレ

Turborepo や Nx などのモノレポ構成では、schema.prismapackages/database/ のような場所にあり、アプリのルートと異なります。このとき Vercel のビルドから見ると生成されたクライアントの場所が node_modules/.prisma/client/ ではなく、別のパスになります。

monorepo/
├── apps/
│   └── web/          ← Next.js アプリ
└── packages/
    └── database/
        ├── schema.prisma
        └── node_modules/.prisma/client/  ← ここに生成される

apps/web/ からは ../../packages/database/node_modules/.prisma/client/ を参照する必要があり、デフォルトの @prisma/client のインポートでは見つからないことがあります。

解決策: output を明示指定する

// packages/database/schema.prisma
generator client {
  provider = "prisma-client-js"
  output   = "./generated/client"
}
// packages/database/index.ts
// ✅ output で指定したパスから直接 re-export
export { PrismaClient } from './generated/client'
// apps/web/lib/prisma.ts
// ✅ パッケージ経由でインポート
import { PrismaClient } from '@your-org/database'

まとめ

Prisma + Vercel で発生するエラーの原因と対策を整理します。

エラー / 症状 原因 対策
PrismaClient is not a constructor prisma generate 未実行 postinstall に追加
Edge Runtime でクラッシュ Edge非対応 runtime = 'nodejs' に変更
コネクションタイムアウト 毎回 new PrismaClient() グローバルシングルトン化
Can't reach database server at '' 環境変数未設定 / 未反映 Vercelダッシュボードで確認・再デプロイ
モノレポでインポートエラー output パスのズレ output を明示指定

まず postinstall: "prisma generate" を追加するだけで大半のケースは解決します。それでも解決しない場合は、Edge Runtimeの使用有無・コネクション管理・環境変数の順に確認してみてください。Serverlessとデータベースの相性問題は最初は分かりにくいですが、一度仕組みを理解すると同じ問題で詰まることはなくなります。