TL;DR
- migration 時:
DIRECT_URL(db.[ref].supabase.co:5432)を必ず使う - runtime(API ルート・
サーバーレス) :DATABASE_URL(pooler.supabase.com:6543, Transaction mode)を使う - 2025 年 2 月 28 日以降、
port 6543 は Transaction mode 専用に なった - Drizzle + Transaction mode では
prepare: falseを設定しないと本番で 500 エラーが 出る
なぜ接続先を分けないといけないのか
NetaPair のprisma migrate deploy を
原因を.env の DATABASE_URL に pooler の URL(port 6543)を
Supabase の
Transaction mode と direct connection の違い
Supabase の
| Transaction pooler | Direct connection | |
|---|---|---|
| ホスト | aws-0-[region].pooler.supabase.com | db.[project-ref].supabase.co |
| ポート | 6543 | 5432 |
| 接続の | トランザクション | セッション |
| prepared statements | 非対応 | 対応 |
SET session_replication_role | 非対応 | 対応 |
| migration | 禁止 | 推奨 |
| Vercel など | 推奨 | 非推奨(接続数爆発) |
Transaction mode は、
prisma migrate deploy や Supabase CLI の db push はSET session_replication_role = 'replica' を
2025 年 2 月以降のポート整理
以前は port 6543 で Session mode を
現在の
- port 6543 → Transaction mode のみ(runtime 専用)
- port 5432 → Session mode または direct connection(migration 向け)
古い設定がport=6543 で migration を
環境変数の設定
Supabase ダッシュボードの Project Settings → Database にTransaction(port 6543)と Direct connection(port 5432)の 2 つを
# .env.local
# ↓ Supabase ダッシュボード → Project Settings → Database → "Transaction" タブからコピー
DATABASE_URL="<Transaction pooler URL (port 6543)>"
# ↓ Supabase ダッシュボード → Project Settings → Database → "Direct connection" タブからコピー
DIRECT_URL="<Direct connection URL (port 5432)>"
Transaction pooler の URL はaws-0-[region].pooler.supabase.com、6543。db.[project-ref].supabase.co、5432 という構成に[project-ref] は Supabase の[region] は ap-northeast-1 などの AWS リージョン。
Prisma での設定
Prisma v6 以前
schema.prisma の datasource ブロックに directUrl をPrismaClient は url を
// schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL") // pooler (port 6543) — runtime
directUrl = env("DIRECT_URL") // direct (port 5432) — migration
}
prisma migrate deploy や prisma db push はdirectUrl を
Prisma v7 以降
Prisma v7.2.0 以降、schema.prisma から URL をprisma.config.ts で migration 時のPrismaPg コンストラクタで
// prisma.config.ts — CLI が参照する (migration 用)
import { defineConfig } from 'prisma/config'
export default defineConfig({
earlyAccess: true,
schema: './prisma/schema.prisma',
migrate: {
async adapter() {
const { PrismaPg } = await import('@prisma/adapter-pg')
// DIRECT_URL を使う — direct connection (port 5432)
return new PrismaPg({ connectionString: process.env.DIRECT_URL! })
},
},
})
// src/lib/db.ts — アプリが参照する (runtime 用)
import { PrismaClient } from '@prisma/client'
import { PrismaPg } from '@prisma/adapter-pg'
// DATABASE_URL を使う — pooler (port 6543)
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! })
export const prisma = new PrismaClient({ adapter })
Drizzle ORM での設定
Drizzle は drizzle.config.ts(migration 用)と runtime の
// drizzle.config.ts — drizzle-kit push/migrate が参照 (migration 用)
import { defineConfig } from 'drizzle-kit'
export default defineConfig({
schema: './src/db/schema.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DIRECT_URL!, // direct connection (port 5432)
},
})
// src/lib/db.ts — API ルートが参照 (runtime 用)
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
import * as schema from '@/db/schema'
// prepare: false は Transaction mode では必須
const client = postgres(process.env.DATABASE_URL!, { prepare: false })
export const db = drizzle(client, { schema })
落とし穴 2 点
prepare: false を忘れると本番だけ落ちる
これもprepare: false をERROR: prepared statement "xxx" already exists が
ローカル(通常の PostgreSQL 直接接続)ではprepare: false で
migration コマンドがハングする
冒頭にDATABASE_URL(port 6543)を directUrl のprisma migrate deploy が
.env に DIRECT_URL をschema.prisma(または prisma.config.ts)に
まとめ
| 用途 | 環境変数 | ホスト | ポート |
|---|---|---|---|
| migration (prisma/drizzle-kit) | DIRECT_URL | db.[ref].supabase.co | 5432 |
| runtime (API ルート) | DATABASE_URL | ...pooler.supabase.com | 6543 |
2025 年 2 月以降、prepare: false を
参照リンク
- Supabase Changelog: Session Mode on Port 6543 廃止
- GitHub Discussion #32755: Session Mode 廃止の
告知 - Prisma 公式 Supabase ガイド(v6)
- Prisma Discussion #28700: directUrl deprecated in v7
- Drizzle ORM: Drizzle with Supabase Database