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_statements above zero in PgBouncer 1.21 and later. Use ?pgbouncer=true on 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.url in prisma.config.ts to the direct URL; see prisma-migrations.
  • Transaction mode resets server state between transactions. Session-level SET, session advisory locks, and LISTEN/NOTIFY do 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; PrismaPg expects 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.