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
```