afterbuild/ops
ERR-315/Prisma · Pool
ERR-315
Timed out fetching a new connection from the connection pool. (More info: https://pris.ly/d/connection-pool)

appears when:When a Vercel serverless function holds its Prisma client open through many concurrent requests without a shared pooler like PgBouncer or Accelerate

Prisma connection pool timeout

Serverless spawns a new Prisma client per cold start. Without PgBouncer or the Neon driver, Postgres runs out of connections and requests queue until Prisma gives up.

Last updated 17 April 2026 · 7 min read · By Hyder Shah
Direct answer
Prisma connection pool timeout on Vercel is almost always a serverless lifecycle mismatch. Fix three things: route through PgBouncer with pgbouncer=true&connection_limit=1 in DATABASE_URL, store the PrismaClient on globalThis so dev reloads do not multiply pools, and use Neon's serverless driver or Prisma Accelerate when you need higher concurrency.

Quick fix for Prisma connection pool timeout

lib/db.ts
typescript
01// lib/db.ts — canonical Prisma client for serverless + Vercel02import { PrismaClient } from "@prisma/client";03 04const globalForPrisma = globalThis as unknown as {05  prisma: PrismaClient | undefined;06};07 08export const db =09  globalForPrisma.prisma ??10  new PrismaClient({11    log: process.env.NODE_ENV === "development" ? ["error", "warn"] : ["error"],12  });13 14if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = db;15 16// .env.production — must include pgbouncer=true and connection_limit=117// DATABASE_URL="postgres://user:pass@pooler.supabase.com:6543/db?pgbouncer=true&connection_limit=1"18// DIRECT_URL="postgres://user:pass@db.supabase.co:5432/db"  # used only for migrations19//20// prisma/schema.prisma21// datasource db {22//   provider  = "postgresql"23//   url       = env("DATABASE_URL")24//   directUrl = env("DIRECT_URL")25// }
Canonical Prisma client + DATABASE_URL. Works on Vercel, Supabase PgBouncer, and dev hot-reload

Deeper fixes when the quick fix fails

01 · Neon serverless driver — best for edge runtime

lib/db.ts
typescript
01// lib/db.ts — Prisma with @neondatabase/serverless over WebSockets02import { PrismaClient } from "@prisma/client";03import { PrismaNeon } from "@prisma/adapter-neon";04import { Pool } from "@neondatabase/serverless";05 06const pool = new Pool({ connectionString: process.env.DATABASE_URL });07const adapter = new PrismaNeon(pool);08 09const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined };10 11export const db =12  globalForPrisma.prisma ??13  new PrismaClient({ adapter });14 15if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = db;
Neon driver over WebSockets — works on Edge runtime and does not need PgBouncer config

02 · Prisma Accelerate — managed pool and edge cache

lib/db.ts
typescript
01// lib/db.ts — Accelerate via the Prisma extension02import { PrismaClient } from "@prisma/client/edge";03import { withAccelerate } from "@prisma/extension-accelerate";04 05const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined };06 07export const db =08  globalForPrisma.prisma ??09  new PrismaClient().$extends(withAccelerate()) as unknown as PrismaClient;10 11if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = db;12 13// .env — DATABASE_URL is an Accelerate URL starting with prisma://14// DATABASE_URL="prisma://accelerate.prisma-data.net/?api_key=..."15// DIRECT_URL="postgres://user:pass@db.neon.tech:5432/db"
Accelerate handles pooling globally and adds a cache — pairs with any Postgres provider

03 · Kill long-running queries in Postgres

supabase/migrations/kill_idle_tx.sql
sql
01-- Supabase SQL editor — cancel any connection idle in transaction for > 60s02select pg_terminate_backend(pid)03from pg_stat_activity04where state = 'idle in transaction'05  and (now() - state_change) > interval '60 seconds';06 07-- Add as a pg_cron job to run every minute08select cron.schedule(09  'kill-idle-in-tx',10  '* * * * *',11  $$select pg_terminate_backend(pid) from pg_stat_activity where state = 'idle in transaction' and (now() - state_change) > interval '60 seconds';$$12);
Safety net — kills zombie transactions that escape Prisma's own cleanup

Why AI-built apps hit Prisma connection pool timeout

Prisma opens a dedicated TCP connection pool per PrismaClient instance. Default pool size is num_physical_cpus * 2 + 1. On a Vercel serverless function that is usually three. Each concurrent invocation runs in its own Node process with its own client and its own pool of three. Ten concurrent requests means thirty Postgres connections. Postgres on Supabase free tier allows sixty total. Three busy API routes saturate the database and Prisma's local pool waits; when the wait exceeds ten seconds it throws Timed out fetching a new connection from the connection pool.

AI builders scaffold const prisma = new PrismaClient() at the top of every file. In development, Next.js hot-reloads on every edit, each reload spawns a new client, and within minutes you have fifty zombie connections that Postgres never closed. Dev-time symptoms match production-time symptoms and both are the same root cause.

The fix for production is a connection pooler outside Prisma. PgBouncer in transaction mode multiplexes many client connections over a small pool of real Postgres connections. Supabase ships a hosted PgBouncer on port 6543. Neon ships a pgbouncer-compatible pooler at pooler.neon.tech. Prisma respects pgbouncer=true in the connection string, which disables prepared statements (PgBouncer transaction mode does not support them) and sets connection_limit=1 so Prisma takes only one connection from the pooler per invocation.

The fix for dev-time pool exhaustion is the global singleton pattern. Store the PrismaClient on globalThis in non-production environments so hot reloads find the existing client and do not open a new pool. In production this is a no-op because each invocation is a fresh Node process. This pattern is well-known but AI-generated code often skips it.

When PgBouncer transaction mode is not enough — for example you use $transaction blocks with long-running queries — switch to the Neon serverless driver (which talks to Neon over WebSockets and scales horizontally) or Prisma Accelerate (which adds a managed pool plus an edge cache). Both are drop-in for most apps.

Prisma connection pool timeout by AI builder

How often each AI builder ships this error and the pattern that produces it.

AI builder × Prisma connection pool timeout
BuilderFrequencyPattern
LovableEvery Prisma scaffoldnew PrismaClient() at top of every file — dev reloads multiply pools
Bolt.newCommonNo pgbouncer=true in DATABASE_URL — goes direct to port 5432
v0CommonNo singleton pattern — hot reload eats all Postgres connections
CursorSometimesCalls fetch() inside db.$transaction — holds connection for seconds
Replit AgentRareIgnores DIRECT_URL — migrations fail through PgBouncer transaction mode

Related errors we fix

Stop Prisma connection pool timeout recurring in AI-built apps

Still stuck with Prisma connection pool timeout?

Emergency triage · $299 · 48h turnaround
We restore service and write the root-cause report.
start the triage →

Prisma connection pool timeout questions

Why does Prisma keep hitting connection pool timeouts on Vercel?+
Every Vercel serverless invocation is a separate Node process. Without a shared connection pooler, each invocation opens a new Postgres connection, holds it for the request duration, and tries to close it on shutdown. Postgres max_connections is typically 100 — three bursty API routes saturate it and the next invocation waits in Prisma's local pool until timeout. Fix with PgBouncer in transaction mode, the Neon serverless driver, or Prisma Accelerate.
What connection_limit should I set on Prisma for serverless?+
Set connection_limit=1 in the DATABASE_URL when you go through PgBouncer transaction mode. Each serverless invocation takes exactly one connection from PgBouncer, executes, and returns it. Without this, Prisma tries to open its own pool of 3+ connections per process, which defeats the pooler. Append ?pgbouncer=true&connection_limit=1 to the DATABASE_URL to get both behaviors.
Should I use Prisma Accelerate or PgBouncer?+
Accelerate is Prisma's managed connection pool plus an edge cache. It handles pooling globally and adds a read-through cache for frequently repeated queries. PgBouncer is cheaper (free with Supabase or a $5 droplet) but only handles pooling. For small AI apps shipping under 10,000 requests a day, PgBouncer is enough. For higher traffic or edge deployments, Accelerate is faster and reduces cold-start latency. You can combine both.
What is a global Prisma instance and why do I need it?+
Serverless functions in dev mode hot-reload, and every reload spawns a new PrismaClient. After five reloads you have five clients, each with its own pool. The fix is to store the client on globalThis and reuse it across reloads. This is a well-known Prisma pattern but AI builders often omit it, causing pool exhaustion in local dev and preview deployments. The snippet in the quick-fix covers the canonical version.
How long does a Prisma pool fix take?+
Fifteen minutes for the DATABASE_URL change and global client pattern. Thirty minutes if you need to switch to Neon's serverless driver or Prisma Accelerate. An hour if transactions are leaking connections and you need to audit every await chain. Emergency Triage at $299 covers the fix plus a load test that hits your three busiest endpoints with 100 concurrent requests to confirm the pool holds.
Next step

Ship the fix. Keep the fix.

Emergency Triage restores service in 48 hours. Break the Fix Loop rebuilds CI so this error cannot ship again.

About the author

Hyder Shah leads Afterbuild Labs, shipping production rescues for apps built in Lovable, Bolt.new, Cursor, Replit, v0, and Base44. our rescue methodology.

Sources