できない.dev

Next.js の開発時に Prisma が「too many connections」で接続できない

Next.js の Fast Refresh でモジュールが再評価されるたびに new PrismaClient() が実行され、開発中だけ接続が増え続けるのが原因。
PrismaClient を globalThis にキャッシュして単一インスタンスを使い回せば解消する。

#prisma#connection#nextjs#hot-reload#dev

公開:

要約

Next.js の開発サーバーは Fast Refresh(hot reload)でファイルを保存するたびにモジュールを再評価します。

このとき PrismaClient を生成するモジュールも作り直され、保存ごとに新しいインスタンスと DB 接続が積み上がります。

結果として開発中だけ接続が増え続け、too many connections(PostgreSQL では sorry, too many clients already)に達します。

解決策は単純で、PrismaClientglobalThis にキャッシュし、開発環境では同じインスタンスを使い回すことです。

よくある原因

  1. hot reload でモジュールが再評価され、new PrismaClient() が繰り返し実行される。
  2. モジュールスコープで直接インスタンスを生成しており、再読み込みのたびに別接続になる。
  3. 開発サーバーを長時間起動したままにして、DB の最大接続数に到達する。

本番ビルドでは hot reload が無いため再現せず、開発時だけ起きるのが特徴です。

解決策

1. globalThis にインスタンスをキャッシュする

公式の Database connections が推奨する書き方です。

// lib/prisma.ts
import { PrismaClient } from "@prisma/client";
 
const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined;
};
 
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
 
if (process.env.NODE_ENV !== "production") {
  globalForPrisma.prisma = prisma;
}

グローバル変数は hot reload で初期化されないため、2 回目以降は既存インスタンスを再利用します。

2. アプリ側は常にこのモジュールを読み込む

import { prisma } from "@/lib/prisma";
 
const users = await prisma.user.findMany();

各所で new PrismaClient() せず、必ずこの単一モジュール経由で使います。

3. 滞留した接続を解放する

すでに接続が詰まっている場合は、開発サーバー(next dev)を一度止めて再起動すれば、開いたままの接続が解放されます。

この記事は役立ちましたか?