docs: add application-side pool sizing to the connecting to Postgres guide (#49927)

Closes DOCS-1312

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Docs update. One technical addition, isolated so the eval can attribute
a score change to it.

I re-ran the preview link on a scratch Eval branch and found that this
PR will resolve the Eval.

## What is the current behavior?

The eval baseline for `build-docs-004-postgres-connection` fails one
check, 3 of 6 runs: the application-side pool cap for a serverless
invocation.

- Two failing runs left `max` unset, which is 10 on the Postgres.js
default.
- One set `max: 5`.

The page says nothing about the application-side pool, so there was
nothing for an agent to read. Every other check passes 6/6, including
the connection string, port, username, and prepared statements. The mode
choice already transmits from the page.

Baseline notes are on
[DOCS-1312](https://linear.app/supabase/issue/DOCS-1312).

## What is the new behavior?

Add a **Configure your client** section to the procedure group. Pool
sizing is its only subject.

- Set the application-side pool to 1 connection per serverless
invocation, and raise it only on evidence.
- Name the trap concretely. Library defaults assume a persistent
backend, and 10 connections is 10 per warm instance, with the instance
count outside your control.
- One Postgres.js sample setting `max` and `prepare`, created at module
scope.
- Cite the [Supavisor
FAQ](https://supabase.com/docs/guides/troubleshooting/supavisor-faq-YyP5tI)
and [Prisma
troubleshooting](https://supabase.com/docs/guides/database/prisma/prisma-troubleshooting),
which already carries the equivalent `connection_limit` guidance for one
ORM. The gap is that the connection guide didn't carry it for readers
not using Prisma.

`prepare: false` is in the sample because a transaction mode sample is
wrong without it, and the page already instructs it. It isn't new
guidance. `ssl: 'require'` is, so it waits for #49928.

## Additional context

PR 3 of 4. Base is #49869.

This ships alone on purpose. It's the only change with baseline evidence
behind it, so a score change after this PR is attributable to one edit.
#49928 carries the rest of the eval feedback and is not expected to move
the score.

**Run the eval against this preview before #49928 lands.**

## Manual testing

1. Open [Connect to your
database](https://docs-git-docs-connecting-to-postgres-pool-size-supabase.vercel.app/docs/guides/database/connecting-to-postgres)
on the deploy preview.
2. Check the table of contents. "Configure your client" appears under
Get your connection string.
3. Read the section. It states 1 connection per invocation and names the
Postgres.js default of 10.
4. Read the sample. It sets `max: 1` and `prepare: false`, and says the
client is created once at module scope.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Documentation**
- Added guidance for configuring application-side Postgres clients when
connecting through Supabase poolers.
- Documented recommended serverless settings, including creating the
client once, limiting connections per invocation, and disabling prepared
statements in transaction mode.
- Added a Postgres.js configuration example and links to relevant
Supavisor FAQ and Prisma troubleshooting resources.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Miranda Limonczenko authored and GitHub committed 2026-09-09 16:39:09 -07:00
1 parent 165582b08e
commit 15484a0e75
1 file changed
+25
@@ -98,6 +98,31 @@ postgresql://postgres:[YOUR-PASSWORD]@db.[PROJECT-REF].supabase.co:6543/postgres
Get this string from the Supabase Dashboard by clicking [Connect](/dashboard/project/_?showConnect=true&method=transaction).
### Configure your client
Your connection library keeps its own pool of connections, separate from the poolers Supabase runs. Configure it for the environment your code runs in.
In a serverless function:
1. Create the client once at module scope, not per request.
2. Set the pool to 1 connection. The client is shared by every invocation on that warm instance, so this caps the instance, not the request.
3. Turn off prepared statements, which [transaction mode](#pooler-transaction-mode) doesn't support.
```ts lib/db.ts
import postgres from 'postgres'
export const sql = postgres(process.env.DATABASE_URL, {
max: 1,
prepare: false,
})
```
Library defaults assume a persistent backend, so they are too high for serverless. [Postgres.js](https://github.com/porsager/postgres) defaults to 10 connections. That is 10 connections for every warm instance of your function, and the number of warm instances isn't something you control. A few dozen instances is enough to exhaust the pool.
Raise the pool above 1 only when you have evidence that concurrent invocations on one instance are queuing for the connection.
For more on sizing an application-side pool, see the [Supavisor FAQ](/docs/guides/troubleshooting/supavisor-faq-YyP5tI). If you use Prisma, [Prisma troubleshooting](/docs/guides/database/prisma/prisma-troubleshooting) covers the equivalent `connection_limit` setting.
### Data APIs and client libraries [#data-apis-and-client-libraries]
The Data APIs let you interact with your database using REST or GraphQL requests. You can use these APIs to fetch and insert data from the frontend, as long as your tables have [Row Level Security](/docs/guides/database/postgres/row-level-security) (RLS) enabled and policies that allow the access. RLS with no policies denies every request.