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 Mode | Behavior |
|---|---|
| Transaction (default) | Server connections are reused per transaction — best multiplexing. Session-level features (LISTEN/NOTIFY, advisory locks, SET held across statements) are not supported. |
| Session | Each client holds a server connection for its entire session. Every Postgres feature works, but pooling only helps when clients disconnect. |
| Statement | Server 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:
| Variable | Points to | Use for |
|---|---|---|
DATABASE_URL | PgBouncer — private network | Normal application queries from inside Railway |
DATABASE_PUBLIC_URL | PgBouncer — TCP proxy | Connecting from outside Railway |
DATABASE_UNPOOLED_URL | Postgres or HAProxy — private network | Operations that require a dedicated session |
DATABASE_PUBLIC_UNPOOLED_URL | Postgres or HAProxy — TCP proxy | Unpooled 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 CONCURRENTLYLISTEN/NOTIFY- Advisory locks (
pg_advisory_lock) SETconfiguration 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:
| Setting | Default | Description |
|---|---|---|
DEFAULT_POOL_SIZE | 20 | Server connections per replica |
MAX_CLIENT_CONN | 1000 | Max 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_URLto point directly at your Postgres service (or HAProxy for HA clusters) - Remove the
DATABASE_UNPOOLED_URLvariable
Railway automatically migrates variable references within your project back to the original endpoint. Hardcoded connection strings outside of Railway must be updated manually.