From c3c741c20e1b3bc7fee102c5133eeccaa31b05a4 Mon Sep 17 00:00:00 2001 From: Szymon Mentel Date: Fri, 25 Sep 2026 10:51:54 +0200 Subject: [PATCH] docs: warn about postgres.js pipelining on Supavisor transaction mode (#50712) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-does #50082 against the redesigned `connecting-to-postgres.mdx` (see [Slack discussion](https://supabase.slack.com/archives/C04JR9DBNQL/p1789991651381399?thread_ts=1788980733.712609&cid=C04JR9DBNQL)). What changed vs. #50082: - `connecting-to-postgres.mdx`: the pipelining caution now lives in the new **Transaction mode limitations** section (the old "Pooler transaction mode" prose it was in got redesigned), and is a short redirect to the Postgres.js guide rather than a full explanation. - `postgres-js.mdx`: keeps the full warning, the `{ prepare: false }` workaround, and now explains *why* pipelining can't just be turned off (`max_pipeline: 0` breaks `sql.begin()`, tracked in porsager/postgres#1189), plus a "contact support" prompt for anyone still stuck, and a note that Supavisor v2.10 will add native pipelining support. - Drops the standalone troubleshooting page from #50082 — the team wasn't confident enough yet to officially point everyone at the `postgres.js` patch, so support is the escalation path for now instead. - Re-adds the `Rule003Spelling.toml` allow-list entry for "pipelining" (not present on `master`). 🤖 Generated with [Claude Code](https://claude.com/claude-code) ## Summary by CodeRabbit * **Documentation** * Clarified that query pipelining is unsupported in transaction mode and may cause hangs or mismatched results. * Documented Postgres.js pipeline behavior, recommended workarounds, and planned native support in a future Supavisor release. * Updated the Postgres.js connection example to disable prepared statements for improved compatibility. * Added a support contact link for assistance with transaction-mode pipeline issues. ## Preview * pipelining mentioned in the Supavisor TX mode: https://docs-git-docs-postgres-js-pipelining-warning-supabase.vercel.app/docs/guides/database/connecting-to-postgres#pooler-transaction-mode * pipelining mentioned in more detail in TX mode limitations: https://docs-git-docs-postgres-js-pipelining-warning-supabase.vercel.app/docs/guides/database/connecting-to-postgres#transaction-mode-limitations * `postgres.js` pipelining warning with even more details: https://docs-git-docs-postgres-js-pipelining-warning-supabase.vercel.app/docs/guides/database/postgres-js --------- Co-authored-by: Claude Sonnet 5 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Miranda Limonczenko --- .../guides/database/connecting-to-postgres.mdx | 18 ++++++++++++++++-- .../content/guides/database/postgres-js.mdx | 10 +++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/apps/docs/content/guides/database/connecting-to-postgres.mdx b/apps/docs/content/guides/database/connecting-to-postgres.mdx index 30002d5662c..8c431c6101e 100644 --- a/apps/docs/content/guides/database/connecting-to-postgres.mdx +++ b/apps/docs/content/guides/database/connecting-to-postgres.mdx @@ -84,6 +84,12 @@ Transaction mode does not support [prepared statements](https://postgresql.org/d + + +Transaction mode does not support [query pipelining](https://www.postgresql.org/docs/current/libpq-pipeline-mode.html). See [Transaction mode limitations](#transaction-mode-limitations) for mode details. + + + ```txt postgresql://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@[POOLER-HOST]:6543/postgres ``` @@ -168,7 +174,7 @@ For more on sizing an application-side pool, see the [Supavisor FAQ](/docs/guide ### Transaction mode limitations -[Transaction mode](#pooler-transaction-mode) returns your connection to the pool after each transaction, so anything that depends on session state doesn't survive between transactions. Three things are affected. +[Transaction mode](#pooler-transaction-mode) returns your connection to the pool after each transaction, so anything that depends on session state doesn't survive between transactions. Four things are affected. **Prepared statements** aren't supported, so turn them off. Each driver does this differently: @@ -185,7 +191,15 @@ For node-postgres, Psycopg, and Rust drivers, see [Disabling prepared statements **Session-level state** is lost between transactions. This covers `set` and `reset`, session-level advisory locks, `listen` and `notify`, and temporary tables. Run them inside the transaction that needs them, or use session mode or a direct connection instead. -Direct connections and session mode support all three, so none of this applies to either. +**Query pipelining** isn't supported: transaction mode returns a connection to the pool as soon as it sees one reply finish, even if the client already queued more queries on it. + +Direct connections and session mode support all four, so none of this applies to either. + + + +`postgres.js` pipelines queries by default, so this combination can hang queries or return mismatched rows — see the [Postgres.js guide](/docs/guides/database/postgres-js) for how to avoid it. + + ### SSL [#connecting-with-ssl] diff --git a/apps/docs/content/guides/database/postgres-js.mdx b/apps/docs/content/guides/database/postgres-js.mdx index 0c4e42b7e8c..ca66bb35f01 100644 --- a/apps/docs/content/guides/database/postgres-js.mdx +++ b/apps/docs/content/guides/database/postgres-js.mdx @@ -38,6 +38,14 @@ hideToc: true To get your connection details, go to the [**Connect** panel](/dashboard/project/_?showConnect=true). Choose [**Transaction pooler**](/dashboard/project/_?showConnect=true&method=transaction) if you're on a platform with transient connections, such as a serverless function, and [**Session pooler**](/dashboard/project/_?showConnect=true&method=session) if you have a long-lived connection. Copy the URI and save it as the environment variable `DATABASE_URL`. + + + `postgres.js` pipelines queries by default. Combined with the [shared pooler transaction mode](/docs/guides/database/connecting-to-postgres#pooler-transaction-mode), this can hang queries or return mismatched rows. `postgres.js` has no working option to turn pipelining off directly: `max_pipeline: 0` breaks `sql.begin()` transactions instead, a known upstream [bug](https://github.com/porsager/postgres/issues/1189). + + For more about pipelining with `postgres.js`, [contact support](/dashboard/support/new). + + + @@ -47,7 +55,7 @@ hideToc: true import postgres from 'postgres' const connectionString = process.env.DATABASE_URL - const sql = postgres(connectionString) + const sql = postgres(connectionString, { prepare: false }) export default sql ```