Neon runs PgBouncer in front of every database in transaction mode, with max_client_conn set to 10,000. That means up to 10,000 clients (serverless function invocations, edge workers, request-per-connection web frameworks) can hold a connection to PgBouncer at once, even though the underlying Postgres has a much smaller max_connections limit.

Why this matters for serverless

Each Postgres connection is a process that consumes RAM, so max_connections scales with compute size:

Compute sizeRAMmax_connections
0.25 CU≈1 GB104
1 CU≈4 GB419
4 CU≈16 GB1,678
9 CU+≈36 GB+4,000 (capped)

Seven connections are reserved for the Neon superuser. So a 0.25 CU compute leaves 97 connections for your app, which a moderately busy serverless workload can exhaust in seconds.

PgBouncer fixes that by multiplexing thousands of short-lived client connections through a smaller pool of real Postgres connections. The pool size per (user, database) combination is 0.9 × max_connections, so a 1 CU compute supports about 377 concurrent active transactions per user/database.

How to opt in

Add -pooler to your endpoint hostname in the connection string:

# Direct
postgresql://user:pass@ep-cool-darkness-123456.us-east-2.aws.neon.tech/dbname

# Pooled
postgresql://user:pass@ep-cool-darkness-123456-pooler.us-east-2.aws.neon.tech/dbname

You can grab the pooled string from the Connect dialog in the Console. Use the pooled connection for serverless functions, edge runtimes, and any framework that opens a connection per request.

Transaction-mode limitations

PgBouncer in transaction mode returns the connection to the pool after each transaction, so session-scoped features like SET, LISTEN/NOTIFY, WITH HOLD CURSOR, and SQL-level PREPARE don't work. Use a direct connection for pg_dump, schema migrations, and logical replication. The full list is in the connection pooling guide.

For edge runtimes that can't hold TCP at all (Cloudflare Workers, Vercel Edge Functions), pair PgBouncer with the Neon serverless driver, which queries Postgres over HTTP or WebSockets.

How other managed Postgres services handle pooling

ProviderPoolerTransport for edge runtimes
NeonPgBouncer per endpoint, up to 10,000 client connectionsHTTP and WebSockets via @neondatabase/serverless
SupabaseSupavisor (shared) and dedicated PgBouncer for paid tiersNone native. Use Edge Functions over the Data API or fetch over HTTP
Aurora / RDS for PostgreSQLRDS Proxy (separate AWS service, hourly cost)TCP only. Edge clients have to route through an HTTP endpoint you build

Supabase ships a shared Supavisor pool with each project in both session (port 5432) and transaction (port 6543) modes. Paid tiers also get a dedicated PgBouncer co-located with the database. Total client connection capacity scales with the compute tier's "max pooler clients" limit. See Connect to your database and Update connection pool settings.

Aurora and RDS use RDS Proxy as the pooling layer. It's billed separately per vCPU-hour and is configured with a MaxConnectionsPercent of the database's max_connections. It speaks Postgres wire protocol over TCP, so edge runtimes that can't open TCP sockets need a separate HTTP layer (API Gateway + Lambda, for example).

Read the full guide

Connection pooling has nuances around pool size per user/database and timeout behavior worth understanding before you ship.