← 記事一覧に戻る

Prisma で PrismaClientInitializationError が出る・DB接続できない時の5つの原因と対策【PostgreSQL / Docker / 本番環境】

Prismaを使っていると、こんなエラーに遭遇することがある。

PrismaClientInitializationError: Can't reach database server at `localhost:5432`

Please make sure your database server is running at `localhost:5432`.

または

PrismaClientInitializationError: Invalid `prisma.user.findMany()` invocation:

The table `public.User` does not exist in the current database.

「ローカルでは動くのに本番でだけ出る」「Docker環境に切り替えたら急に出た」「Vercelにデプロイしたら繋がらない」といった状況で詰まるケースが多い。

この記事では、よくある5つの原因とそれぞれの対処法を具体的なエラーメッセージとコード例とともに解説する。


よくある症状

  • PrismaClientInitializationError: Can't reach database server
  • PrismaClientInitializationError: Invalid prisma.xxx invocation(テーブルが存在しない)
  • Environment variable not found: DATABASE_URL
  • PrismaClientKnownRequestError: Timed out fetching a new connection from the connection pool
  • ローカルは動くがVercel・RailwayなどのCI/CD後に接続できない

原因1: DATABASE_URL が設定されていない・フォーマットが間違っている

最も多い原因.env ファイルが存在しない、または DATABASE_URL の接続文字列フォーマットが間違っている。

症状:

Environment variable not found: DATABASE_URL.
  --> schema.prisma:9
   |
 9 |   url = env("DATABASE_URL")

正しい PostgreSQL の接続文字列フォーマット:

postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=public

よくある間違いと正しい書き方:

# ❌ 間違い: postgres:// スキームを使っている(古い表記)
DATABASE_URL="postgres://myuser:mypassword@localhost:5432/mydb"

# ✅ 正しい: postgresql:// を使う
DATABASE_URL="postgresql://myuser:mypassword@localhost:5432/mydb?schema=public"
# ❌ 間違い: パスワードに特殊文字が含まれている(URLエンコードが必要)
DATABASE_URL="postgresql://myuser:p@ss#word@localhost:5432/mydb"

# ✅ 正しい: 特殊文字をURLエンコードする
# @ → %40, # → %23, $ → %24
DATABASE_URL="postgresql://myuser:p%40ss%23word@localhost:5432/mydb"

確認コマンド:

# .env が読み込まれているか確認
npx prisma db pull
# 正常なら現在のDBスキーマが取得される
# エラーなら接続文字列を見直す

注意: Prismaは .env ファイルを自動で読み込むが、.env.local.env.developmentデフォルトでは読み込まれない。Next.jsやViteが読み込んでいる環境変数ファイルとは別物なので注意。


原因2: prisma generate が実行されていない

prisma generate を実行していないか、schema.prisma を変更後に再実行し忘れると、Prisma Clientのコードが古いままになり実行時エラーになる。

症状:

Error: @prisma/client did not initialize yet. Please run "prisma generate" and try to import it again.

または型エラー:

Property 'newField' does not exist on type 'User'.

対処法:

# Prisma Clientを再生成
npx prisma generate

CI/CDパイプラインでの対策(GitHub Actionsの例):

# .github/workflows/deploy.yml
jobs:
  deploy:
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npx prisma generate  # ← これを必ず追加
      - run: npm run build

package.jsonpostinstall に追加する方法(推奨):

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

こうすると npm install の後に自動で prisma generate が走るため、CI/CD環境でも忘れずに実行される。VercelやRailwayなどのホスティングサービスも npm install を実行するので、これを設定しておくと安心。


原因3: Docker 環境でのネットワーク設定ミス

Docker Composeで開発環境を構築している場合、Node.jsアプリとDBコンテナが別のコンテナとして動いているのに、DATABASE_URLlocalhost を指定してしまうケースがある。

症状:

PrismaClientInitializationError: Can't reach database server at `localhost:5432`

原因: Dockerコンテナ内の localhost はコンテナ自身を指す。PostgreSQLは別のコンテナで動いているため、localhost では到達できない。

典型的な docker-compose.yml:

version: '3.9'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      # ❌ 間違い: コンテナ内のlocalhostはPostgreSQLではない
      DATABASE_URL: "postgresql://postgres:password@localhost:5432/mydb"
    depends_on:
      - db

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: password
      POSTGRES_DB: mydb
    ports:
      - "5432:5432"

正しい設定:

version: '3.9'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      # ✅ 正しい: サービス名(db)をホスト名として使う
      DATABASE_URL: "postgresql://postgres:password@db:5432/mydb"
    depends_on:
      db:
        condition: service_healthy  # DBの起動を待ってからappを起動

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: password
      POSTGRES_DB: mydb
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

depends_on だけでは不十分な理由: depends_on はコンテナの起動を待つだけで、PostgreSQLが接続を受け付けられる状態(ready)になるまでは待たない。healthcheck + condition: service_healthy を組み合わせることで確実に接続できるようになる。

ローカル開発時の .env とDocker内の環境変数を分ける方法:

# .env(ローカルのnpx ts-node等から直接実行する場合)
DATABASE_URL="postgresql://postgres:password@localhost:5432/mydb"

# .env.docker(docker-compose内のappコンテナ用)
DATABASE_URL="postgresql://postgres:password@db:5432/mydb"
# docker-compose.yml
services:
  app:
    env_file:
      - .env.docker  # Dockerコンテナ専用の環境変数ファイルを使う

原因4: 本番環境(Supabase / Neon / PlanetScale)でのSSL設定不足

SupabaseやNeon、PlanetScaleなどのマネージドDBサービスは、本番環境でSSL接続を必須としている場合がある。SSL設定なしで接続しようとするとエラーになる。

症状:

PrismaClientInitializationError: SSL connection is required. Please use connection string with SSL enabled.

または:

Error: SSL/TLS required

Supabase の接続文字列(正しい例):

# ✅ sslmode=require を必ず付ける
DATABASE_URL="postgresql://postgres:[PASSWORD]@db.[PROJECT-ID].supabase.co:5432/postgres?sslmode=require"

Neon の接続文字列(正しい例):

# ✅ Neonはsslmode=require + pgbouncer=true(コネクションプーリング使用時)
DATABASE_URL="postgresql://user:password@ep-xxx.us-east-2.aws.neon.tech/neondb?sslmode=require&pgbouncer=true"

PrismaのSSL設定(schema.prismaで設定する方法):

// schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
  // 自己署名証明書を使う場合(開発環境)
  // relationMode = "prisma"
}

自己署名証明書(self-signed certificate)を使うDocker環境でSSLエラーが出る場合:

# 開発環境では sslmode=disable でSSLを無効化
DATABASE_URL="postgresql://postgres:password@localhost:5432/mydb?sslmode=disable"

原因5: サーバーレス環境でのコネクションプール枯渇

VercelやAWS Lambdaなどのサーバーレス環境では、リクエストごとに新しい関数インスタンスが起動する。Prismaのデフォルト設定ではインスタンスごとにコネクションプールを作るため、大量のリクエストが来るとDBのコネクション上限を超えてしまう。

症状:

PrismaClientKnownRequestError: Timed out fetching a new connection from the connection pool.
(More info: http://pris.ly/d/connection-pool)

または:

Error: sorry, too many clients already

原因: PostgreSQLのデフォルトの最大コネクション数は通常100。Vercelの場合、無料プランでは最大で数十の関数インスタンスが同時に起動し、それぞれがPrismaのコネクションプール(デフォルト: CPUコア数 × 2 + 1)を確保しようとする。

対策1: コネクション数を制限する

# connection_limit=1 にするとインスタンスあたり1接続に制限
DATABASE_URL="postgresql://user:password@host:5432/db?connection_limit=1&pool_timeout=20"

対策2: Prisma Accelerate(旧Data Proxy)を使う

Prismaが提供するコネクションプーリングサービス。サーバーレス環境に最適化されている。

# Prisma Accelerateの接続文字列
DATABASE_URL="prisma://accelerate.prisma-data.net/?api_key=xxx"

対策3: PgBouncerをプロキシとして挟む

NeonやSupabaseはPgBouncerを内蔵している。接続文字列に pgbouncer=true を付けることで利用できる。

# Neon with PgBouncer
DATABASE_URL="postgresql://user:password@ep-xxx.neon.tech/neondb?sslmode=require&pgbouncer=true"
// schema.prisma: pgbouncer使用時はdirectUrlも設定する(マイグレーション用)
datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")       // PgBouncer経由(アプリ用)
  directUrl = env("DIRECT_URL")         // 直接接続(prisma migrate用)
}

対策4: サーバーレス環境でのPrismaClientシングルトン

Next.jsでホットリロード時にPrismaClientが複数インスタンス化される問題(開発環境でwarningが出る)への対処:

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

const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined
}

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

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

マイグレーション関連のエラー

接続自体はできているのに、テーブルが存在しないエラーが出る場合はマイグレーションの未実行が原因。

# 開発環境:マイグレーションを実行
npx prisma migrate dev

# 本番環境:マイグレーションを適用(マイグレーションファイルが必要)
npx prisma migrate deploy

# スキーマをDBに強制同期(開発環境のみ。本番では使わないこと)
npx prisma db push

migrate devmigrate deploy の違い:

コマンド 用途 マイグレーションファイル
migrate dev 開発環境 生成される
migrate deploy 本番環境 既存のファイルを適用
db push プロトタイピング 生成されない

まとめ

PrismaでDB接続できない時の5つの原因と対策:

原因 症状 対策
DATABASE_URLの設定ミス Environment variable not found URLフォーマット確認・特殊文字のエンコード
prisma generate未実行 did not initialize yet npx prisma generate / postinstallに追加
Dockerネットワーク設定 Can't reach database server at localhost サービス名(db)をホスト名に使う
SSL設定不足 SSL connection is required 接続文字列に ?sslmode=require を追加
コネクションプール枯渇 Timed out fetching a new connection connection_limit=1 / PgBouncer / Prisma Accelerate

Prismaのエラーは「接続文字列の問題」「クライアント未生成」「インフラ設定」の3種類に大別できる。まずは npx prisma db pull で接続確認し、次に prisma generate の実行忘れを確認するという順番でデバッグすると効率的だ。