🎃

Next.js + SupabaseでPrismaが接続できない問題の解決法

に公開

はじめに

Next.js 15のApp RouterとSupabaseを使った開発中に、以下のようなデータベース接続エラーに遭遇したので今後の開発する際の備忘録も兼ねて残しておきます

結論
なぜServer Actionsを使う場合にSession Poolingが必須なのか

環境

  • Next.js: 15.5.6
  • Prisma: 6.18.0
  • Supabase(PostgreSQL)

発生したエラー

フォーム送信時にServer Actionsを使ってデータベースに保存しようとすると、以下のエラーが発生しました。

// src/app/actions/articles/save-article.ts
"use server";

import prisma from "@/lib/prisma";

export async function saveArticle(articleData: ArticleDataProps, userId: string) {
  await prisma.article.create({  // ← ここでエラー
    data: {
      userId,
      ...articleData,
    },
  });
}

エラーメッセージ:

Can't reach database server at `db.ijbbodiayaqhhhivfntb.supabase.co:5432`

解決策について

解決には、DATABASE_URLをSession Pooling用に変更する必要がありました。

なぜSession Poolingが必要なのか?

Direct Connection(ポート5432)で接続することの問題点

┌─────────────────┐
│ Server Action   │ ──→ 新しい接続
├─────────────────┤
│ Server Action   │ ──→ 新しい接続
├─────────────────┤
│ Server Action   │ ──→ 新しい接続  ← 接続数上限に到達!
└─────────────────┘

Next.js 15のServer Actionsはサーバーレス的に動作しますが、以下の挙動によりSupabaseとの相性があまり良くないため問題が起きてしまっていました。

  • 各リクエストごとに新しいインスタンスが起動
  • 毎回新しいデータベース接続を確立しようとする
  • PostgreSQLの接続数には上限がある(Supabase無料プランは60接続)
  • すぐに接続数上限に達してしまう

Session Pooling(ポート6543)の仕組み

┌─────────────────┐
│ Server Action   │ ──┐
├─────────────────┤   │
│ Server Action   │ ──┼──→ PgBouncer ──→ 接続プール ──→ PostgreSQL
├─────────────────┤   │
│ Server Action   │ ──┘
└─────────────────┘

Session Poolingの利点

  • Supabase提供のPgBouncerが接続を管理
  • 接続を再利用するため、新しい接続を都度確立しない
  • サーバーレス環境に最適化
  • 接続枯渇の問題を回避

Direct Connectionが有効なケースとそうではない場合について

Direct Connectionが使えるケース

環境 理由
Express/Fastifyなどの常駐サーバー 接続プールが維持される
VPS/EC2でのNext.jsサーバー サーバーが常駐している
Prisma Migrate実行時 CLIコマンドはDirect Connectionが必須

Direct Connectionが望ましくない(非推奨)ケース

環境 理由
Next.js App Router + Server Actions サーバーレス的動作のため
Vercel/Netlifyデプロイ サーバーレス環境
Edge Runtime 軽量ランタイムのため

ベストプラクティス:両方のURLを設定

実際の開発では、両方のURLを用意するのが方法としては有効です。

.envファイル

# Session Pooling(アプリケーション実行時)
DATABASE_URL="postgresql://postgres:[PASSWORD]@aws-0-ap-northeast-1.pooler.supabase.com:6543/postgres?pgbouncer=true"

# Direct Connection(Prisma Migrate実行時)
DIRECT_URL="postgresql://postgres:[PASSWORD]@db.xxx.supabase.co:5432/postgres"

Prisma Schema

// prisma/schema.prisma
datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")     // アプリケーション用
  directUrl = env("DIRECT_URL")       // マイグレーション用
}

Supabaseでのenv用の文字列取得方法について

※UIの変更などにより変わる可能性があります。
(画像撮影時点の)2025/10/24時点においては有効でした)

まとめ

  • Next.js 15のApp Router + Server Actionsを使う場合(Direct Connection(ポート5432)はサーバーレス環境では接続枯渇が発生可能性がある為)Session Pooling(ポート6543) にすることでこのエラーは発生を防ぐことができます。
  • 開発時にはmigrateを行うことが発生するため.envに両方のURLを設定し、schema.prismaで使い分けることで設定の手間が省け、開発効率が向上するため得策です。

Supabaseを使って開発を進めていたら少し困ったので皆さんも先に設定しておくと良いかなと思います!!

参考資料

Discussion