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 serverPrismaClientInitializationError: Invalid prisma.xxx invocation(テーブルが存在しない)Environment variable not found: DATABASE_URLPrismaClientKnownRequestError: 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.json の postinstall に追加する方法(推奨):
{
"scripts": {
"postinstall": "prisma generate"
}
}
こうすると npm install の後に自動で prisma generate が走るため、CI/CD環境でも忘れずに実行される。VercelやRailwayなどのホスティングサービスも npm install を実行するので、これを設定しておくと安心。
原因3: Docker 環境でのネットワーク設定ミス
Docker Composeで開発環境を構築している場合、Node.jsアプリとDBコンテナが別のコンテナとして動いているのに、DATABASE_URL に localhost を指定してしまうケースがある。
症状:
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 dev と migrate 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 の実行忘れを確認するという順番でデバッグすると効率的だ。
