← back to stream

Postgres connection pooling

Opening a Postgres connection is expensive — each connection is a forked backend process, using ~10MB of memory. The database has a hard cap (max_connections, default 100), and exceeding it fails new connections outright. A connection pool sits between the application and Postgres, maintains a fixed number of real connections, and lends them to application workers as needed. Two kinds: client-side pools (built into every ORM and driver — pg.Pool in Node, HikariCP in Java) solve the per-worker connection churn but scale poorly if you have many worker processes, each with its own pool. Server-side pools like PgBouncer sit in front of Postgres and multiplex thousands of client connections onto a small number of backend connections — essential once you have multiple app servers, serverless functions, or anything that spawns processes. Pool modes matter: session (one backend per client), transaction (backend released on commit — the common choice), statement (most aggressive, but breaks anything that needs state across statements).