Overview
Every PrismaClient owns a connection pool, and in Prisma 7 the underlying Node driver sets that pool’s behavior. Long-lived servers need a sized pool; serverless and edge runtimes multiply pools across instances and need an external pooler. Decide the pool size and the pooler before you scale, not after the first too many connections error.
Configure the pool on the adapter, not the URL
The Prisma 6 URL parameters connection_limit, pool_timeout, connect_timeout, and max_idle_connection_lifetime no longer work. Pass driver options to the adapter.
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL,
max: 10, // pool size
connectionTimeoutMillis: 5_000,
idleTimeoutMillis: 300_000,
})The pg defaults differ from Prisma 6: max is 10, connectionTimeoutMillis is 0 (wait forever), and idleTimeoutMillis is 10 seconds. Set a connection timeout explicitly so an exhausted pool fails fast instead of hanging. Size the pool so instances times max stays under the database’s max_connections or the pooler’s client limit; see postgres.
Put PgBouncer in transaction mode in front of serverless and large fleets
PgBouncer multiplexes many client connections onto few database connections. Transaction mode is the one Prisma Client works with.
- Set
max_prepared_statementsabove zero in PgBouncer 1.21 and later. Use?pgbouncer=trueon the URL only with PgBouncer older than 1.21. - Use two URLs. The application connects through the pooler. The Prisma CLI needs a direct connection because the schema engine does not support pooling, so set
datasource.urlinprisma.config.tsto the direct URL; see prisma-migrations. - Transaction mode resets server state between transactions. Session-level
SET, session advisory locks, andLISTEN/NOTIFYdo not work through it; give those code paths a separate direct connection.
On Supabase, use the transaction pooler for serverless and a direct or session connection for persistent servers; see supabase.
Keep one client per process in serverless runtimes
A cold container creates its own client and pool. A traffic spike of 100 containers opens up to 100 times max connections. Create the client at module scope so warm invocations reuse it, and do not call $disconnect per invocation. Keep max low per instance and let the pooler absorb the burst. See prisma-client.
Use Accelerate through accelerateUrl, without an adapter
Prisma Accelerate is a managed pooler and cache. It is the one setup that takes no driver adapter. Install @prisma/extension-accelerate, use a prisma:// or prisma+postgres:// URL, and pass it as accelerateUrl.
import { PrismaClient } from "./generated/prisma/client"
import { withAccelerate } from "@prisma/extension-accelerate"
const prisma = new PrismaClient({
accelerateUrl: process.env.DATABASE_URL,
}).$extends(withAccelerate())
await prisma.user.findMany({ cacheStrategy: { ttl: 60, swr: 60 } })- Never pass an Accelerate URL to a driver adapter;
PrismaPgexpects a direct connection string and fails. - For serverless and edge bundles, generate with
npx prisma generate --no-engine. - Caching is opt-in per query through
cacheStrategy.