Postgres
Scaling

Keeping Postgres Connections Under Control as Your App Scales

Count Postgres pools across app processes, jobs, and overlapping releases. Check waits and the database tier’s limits before adding instances.

Forte TeamPublished October 29, 2026Updated November 8, 20266 min read

More traffic arrives at a Node order API that shares its Postgres database with a reporting job. To keep up, the team adds API instances, each with processes that open their own pools of database connections. Together the pools reach a connection limit, so requests start waiting even while Postgres still has CPU to spare.

When you size the pools, count the connections every app process, job, and tool can open. Include the old and new processes that may run at the same time during a release, then compare the total with the slots your host allows and leave room for admin work.

Count where the pools are created

A connection pool keeps connections ready so requests can reuse them. Consider Parcel, an example API where each process creates a pool with its own limit. If Parcel runs six instances with four processes each and a limit of ten per pool, the API alone can ask for 240 connections.

Check how the app starts processes before using the instance count to estimate connections. Count schema change tasks, admin tools, and jobs that create their own clients too, since they can hold connections open even when they have no work to do.

Postgres limits connections with max_connections, and some slots may be reserved for users with special rights. Raising the limit also makes the server use more resources. Start with the provider's limits and the server settings, then decide how many slots the app may use. PostgreSQL connection settings

Include the busiest release moment

During a rollout, Parcel may have more processes than usual because the old and new versions can hold connections at the same time. Use the highest process count you expect during that overlap when you build the budget.

ClientIllustrative maximumPool limit for eachPossible connections
API processes during a rollout12448
Reporting job processes236
Migration task111
Admin and monitoring allowanceReserved shareN/A5
Total planned use60

Use these figures as an example of the calculation, then check your own provider's limits before choosing a pool size. A per-user limit can stop one client from opening more connections even while the server has free slots.

Check the total against each limit that applies. Leave a margin for work you may need during an incident. If every available slot belongs to normal app traffic, an engineer may struggle to connect when the app starts failing.

Find out why a connection stays busy

A request may wait because the pool is too small, because a query or transaction is taking a long time, or because the app failed to return a connection after an error. Measure how often requests wait and for how long, then compare those waits with query times and server load. If slow queries are holding the connections, adding slots can give the same database more work before it finishes the queries already running.

Postgres's pg_stat_activity shows session activity, subject to the viewing user's rights. Look for long queries and sessions left idle inside a transaction. Avoid sharing query text that includes private values. PostgreSQL activity statistics

Check that the code returns each borrowed connection after both success and failure. Close the transaction before waiting on an outside API where possible, because that wait can hold a connection the app could otherwise use for database work.

Put time limits on queries and pool waits. A request should fail in a way you can see and handle. An endless wait lets more requests pile up behind it.

Test the failure path as well as peak traffic

In staging, make Parcel run a slow query and a request that fails partway through. Watch whether the borrowed connections return to the pool. After the test traffic stops, check whether the pool is still stuck at its limit. If it is, inspect how the app returns each connection.

Then test the peak process count the team plans to allow, including rollout overlap. Record errors, pool waits, query time, and database load. An average response time can hide a small group of requests that wait until they time out.

Use the results to set the app's highest instance count and its pool size together. If the database is already busy when requests begin to wait, check query plans, indexes, and transaction length to see whether it can finish each unit of work faster.

Check what a transaction pooler changes

A transaction pooler lets many client connections share fewer database connections. It lends a server connection for a transaction, then can give that server connection to another client.

Because the next transaction may get a different server connection, check any features that rely on a lasting session. These include session settings, some locks, temporary tables, notifications, and prepared statements. Check that the pooler's mode and version support the features your driver uses.

Where your provider supports a direct connection, use it for migrations and work that needs a lasting session. Count those direct clients in the same database budget. The pooler helps clients share connections, while CPU, storage capacity, and high availability depend on the database setup.

Fit the budget to Forte's tier

Forte managed Postgres is open beta. Shared databases use a transaction-mode pooled endpoint. The shared tier allows five concurrent connections per database user across all Service instances. Forte creates a role for each connected Service, so check the total pool use for that role across its processes and instances. Forte connection guide

If two Parcel processes each have a pool capped at three, they can ask for six connections under one Service role. That already exceeds the documented limit of five before a rollout adds another process. Size the pools for the rollout overlap and test what happens when a request has to wait.

Dedicated Postgres is in closed alpha. It offers a pooled port at 6432 and a direct port at 5432. Forte's docs require prepared statements to be disabled on the transaction-pooled path and warn against relying on session state between transactions. Dedicated databases run on one node. Forte pooled and direct access

Read the app's settings before you connect it. Match both the variable names and the connection-string format to the driver. On dedicated Postgres, map a direct URL for migrations while keeping suitable app queries on the pooled URL. Connecting a database creates the Service role, sets the mapped variables, and redeploys the Service.

Use the database's connection and query metrics alongside app pool waits. Before raising Service capacity, fill in the rollout row of the budget. More than one provisioned instance or a non-default Service size requires verified billing. Forte database tiers, Forte Service quotas

Start with the database connection guide. Count Parcel's real processes and pools, then test the busiest supported state with the tier it will use.

Check your pools before adding instances

Count the app and job processes that may run at once, then add their pool limits. Share the totals and your migration needs without credentials.

Connect Your SaaS to Managed PostgreSQL on Forte
Databases
Operations

Connect Your SaaS to Managed PostgreSQL on Forte

Connect a SaaS app to Postgres on Forte. Check driver settings, connection pools, data access, and the restore options for your chosen tier.

5 min read
Choosing Backup Retention for a Small Postgres App
Postgres
Cost

Choosing Backup Retention for a Small Postgres App

Budget for Postgres backups using stored backup data, any included allowance, and the cost of running a restored copy during a test.

6 min read