Short answer
Each replica gets its own connection pool, because each replica is a separate container running its own copy of your application. Railway does not provide a project-level pool abstraction — pooling lives entirely inside your process, so N replicas means N independent pools. Pool size is whatever your application configures (typically via environment variables), not a platform-wide default. When one replica exceeds its hard memory cap, the container runtime OOM-kills that replica alone; its pool dies with it, and the load balancer keeps routing to the survivors.
Likely explanation vs. confirmed facts
Confirmed by how the platform is built: replicas are isolated containers with hard CPU/memory caps, and internal traffic reaches them through private DNS names behind a load balancer. That architecture makes per-replica pools the only possibility — there is no shared in-memory state between containers, and a connection pool is in-process state.
Likely, but verify for your plan: the load balancer is generally unaware of an individual replica's pool saturation. If one replica exhausts its pool, requests routed to it queue or fail rather than being redirected. Treat this as expected behavior for typical L4/L7 balancing, not a documented guarantee.
What happens during burst traffic
Two distinct failure modes get conflated here:
- Pool exhaustion: an application-level event. New requests wait for a free connection or time out. The replica stays alive; other replicas are unaffected.
- Memory cap breach: a platform-level event. The container is killed and restarted. In-flight connections are severed, and the database may hold orphaned server-side connections until its idle timeout reaps them.
A burst can trigger the second via the first: an exhausted pool with a large waiting queue inflates memory, tipping the replica over its cap.
The scaling trap that matters more
The real risk of horizontal scaling is multiplicative: total database connections = replicas × max_pool_size. Scaling from 2 to 8 replicas with a pool of 20 jumps potential connections from 40 to 160, which can exceed your database's connection limit even though each replica looks healthy.
Practical steps
- Size the pool per replica so that
replicas × pool_size < database_max_connections, leaving headroom for migrations and admin sessions. - Set pool acquire timeouts so saturated replicas fail fast instead of queuing into an OOM.
- Verify per-replica isolation: scale from 1 to N and watch the database's active connection count grow roughly linearly.
- Verify cap behavior: induce memory pressure in one replica and confirm only that instance restarts while others keep serving.
One detail that changes the recommendation: which database and driver are you using? Some drivers support external poolers (e.g., PgBouncer-style transaction pooling), which would let you scale replicas without scaling total connections.