|Docs

PostgreSQL Connection Pooling

Railway can add PgBouncer as a connection pooler in front of your PostgreSQL service. PgBouncer multiplexes many application connections into a smaller pool of server connections, reducing overhead and allowing your database to serve far more concurrent clients than max_connections alone would permit.

PgBouncer works with both standalone Postgres and Postgres HA clusters. When added to an HA cluster, it sits in front of HAProxy.

Adding PgBouncer

Open your Postgres service and navigate to Database → Config → Connection Pooling. Click Add PgBouncer.

Before confirming, select a pool mode:

Pool ModeBehavior
Transaction (default)Server connections are reused per transaction — best multiplexing. Session-level features (LISTEN/NOTIFY, advisory locks, SET held across statements) are not supported.
SessionEach client holds a server connection for its entire session. Every Postgres feature works, but pooling only helps when clients disconnect.
StatementServer connections are reused per statement. Multi-statement transactions are not allowed.

Transaction mode is the right choice for most applications. Use session mode if your application relies on session-scoped features that are incompatible with transaction pooling.

After confirming, Railway stages the changes. Deploy to complete the setup.

Connection strings

Once PgBouncer is deployed, four connection variables are available:

VariablePoints toUse for
DATABASE_URLPgBouncer — private networkNormal application queries from inside Railway
DATABASE_PUBLIC_URLPgBouncer — TCP proxyConnecting from outside Railway
DATABASE_UNPOOLED_URLPostgres or HAProxy — private networkOperations that require a dedicated session
DATABASE_PUBLIC_UNPOOLED_URLPostgres or HAProxy — TCP proxyUnpooled connections from outside Railway

Railway automatically migrates any service within your project that references your Postgres variables to point to PgBouncer. Hardcoded connection strings outside of Railway must be updated manually.

When to use

Use DATABASE_UNPOOLED_URL for operations that require a dedicated server connection:

  • Schema migrations — most migration tools open a transaction that spans the entire migration run
  • CREATE INDEX CONCURRENTLY / DROP INDEX CONCURRENTLY
  • LISTEN / NOTIFY
  • Advisory locks (pg_advisory_lock)
  • SET configuration values that must persist across statements

For everything else, use DATABASE_URL.

Scaling PgBouncer

The PgBouncer Overview panel (available from the cluster view once PgBouncer is deployed) lets you scale the number of PgBouncer replicas from 1 to 6. Each replica multiplies both client capacity and the number of server connections open to Postgres:

SettingDefaultDescription
DEFAULT_POOL_SIZE20Server connections per replica
MAX_CLIENT_CONN1000Max client connections per replica

With 1 replica: up to 1,000 clients share 20 server connections. With 3 replicas: up to 3,000 clients share 60 server connections.

Make sure the total server connections across all replicas (DEFAULT_POOL_SIZE × replicas) stays within your Postgres max_connections limit. The PgBouncer Overview will warn you when server connections approach that limit.

Changing the pool mode

You can change the pool mode at any time from the PgBouncer Overview panel. The change is staged and takes effect on the next PgBouncer deployment — it does not restart your database.

Removing PgBouncer

To remove PgBouncer, click Remove in the PgBouncer Overview, or navigate to Database → Config → Connection Pooling → Remove PgBouncer.

Removing PgBouncer will:

  • Drop all active PgBouncer connections
  • Restore DATABASE_URL to point directly at your Postgres service (or HAProxy for HA clusters)
  • Remove the DATABASE_UNPOOLED_URL variable

Railway automatically migrates variable references within your project back to the original endpoint. Hardcoded connection strings outside of Railway must be updated manually.