Files
supabase/apps/docs/content/guides/database/connecting-to-postgres/serverless-drivers.mdx
Miranda Limonczenko bc102876bb docs: apply the rest of the connecting to Postgres feedback (#49928)
Closes FDBKIN-31335
Closes FDBKIN-13040
Closes FDBKIN-8653
Closes FDBKIN-19912
Closes DOCS-740

## 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. While we are revising this document, this PR gathers docs
feedback via AI magic and applies that feedback.

## What is the current behavior?

These findings stand on feedback intake rather than on the baseline.
Worth doing, and the eval won't show a score change for any of them.

- **Nothing explains the pooler host.** #49868 switched the strings to
`[POOLER-HOST]`, but the page never says why you can't compose the host,
and agents that recite `aws-0` get `Tenant or user not found`.
agent-skills#92.
- **The page gives the instruction to turn prepared statements off, but
not the flag.** It also links the GitHub discussion rather than the
troubleshooting entry that mirrors it. FDBKIN-8248, FDBKIN-7883.
- **SSL goes undiscussed.** Four of six eval runs set `ssl: 'require'`
unprompted.
- **The pooled username format only appears inside example strings**,
never as a rule. DOCS-740, FDBKIN-19912.
- **Third-party tools have no answer.** Session mode is the right one,
and the decision table had no row for a BI client or database GUI at
all. FDBKIN-8653.
- **Only one of transaction mode's three limitations is documented.**
FDBKIN-13040 names prepared statements, cursors, and session-level
settings. The page covered prepared statements.

## What is the new behavior?

- Tell the reader to copy the host, port, and username rather than
typing the placeholders, and explain the pooler cluster index next to
the reference table. The placeholders themselves changed in #49868.
- State the username rule: direct connections and the dedicated pooler
use `postgres`, shared pooler connections use `postgres.<project-ref>`.
- Add a per-driver prepared statements table for Postgres.js, Drizzle,
Prisma, asyncpg, and JDBC, and link [Disabling prepared
statements](https://supabase.com/docs/guides/troubleshooting/disabling-prepared-statements-qL8lEL)
for the rest. Add JDBC's `prepareThreshold=0` to that entry too, so the
two pages agree.
- Document SSL: `require` rather than the `prefer` default, which falls
back to plaintext.
- Link the `CONNECT_TIMEOUT` entry for stale sockets in frozen
serverless runtimes.
- Add a decision table row for a third-party tool, and point at
Quickstarts for named tools.
- Cover all three transaction mode limitations. Cursors work inside a
single transaction only, and session-level state is lost between
transactions: `set` and `reset`, session-level advisory locks, `listen`
and `notify`, and temporary tables. Renamed the section from "Prepared
statements", since it now covers the cause rather than one symptom.
- Promote Configure your client to an H2 and fold the SSL certificate
section into it. The table of contents only renders H2 and H3, so the
client settings were invisible as H4s.


## Manual testing

1. Open [Connect to your
database](https://docs-git-docs-connecting-to-postgres-technical-supabase.vercel.app/docs/guides/database/connecting-to-postgres)
on the deploy preview.
2. Read the Get your connection string lead-in. It tells you to copy the
host, port, and username rather than typing the placeholders.
3. Check the table of contents. Configure your client is an H2 with
Application-side pool size, Prepared statements, SSL, and Stale
connections under it.
4. Follow the prepared statements link. It lands on the in-docs
troubleshooting entry, not GitHub.
5. Open the [endpoint
reference](https://docs-git-docs-connecting-to-postgres-technical-supabase.vercel.app/docs/guides/database/connecting-to-postgres#endpoints-and-ip-versions).
The table shows `aws-[INDEX]-[REGION]`, and the prose below explains the
index and the username rule.
6. Read the decision table. It has a row for a third-party BI client or
database GUI, pointing at session mode.
7. Read [Transaction mode
limitations](https://docs-git-docs-connecting-to-postgres-technical-supabase.vercel.app/docs/guides/database/connecting-to-postgres#transaction-mode-limitations).
It covers prepared statements, cursors, and session-level state.



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

## Documentation

- Expanded the Postgres connection guide with clearer client
configuration guidance, including pool sizing, SSL, stale connections,
and transaction mode limitations.
- Added recommendations for BI tools and database GUIs using the shared
pooler.
- Clarified connection strings, pooler hosts, usernames, ports, and IP
version behavior.
- Updated serverless driver guidance for transaction mode configuration.
- Added JDBC troubleshooting instructions for disabling prepared
statements with `prepareThreshold=0`.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-09 16:49:42 -07:00

148 lines
6.0 KiB
Plaintext

---
id: 'serverless-drivers'
title: 'Serverless drivers'
description: 'Connect to your Postgres database from a serverless environment'
subtitle: 'Choose a driver for connecting to your Postgres database from a serverless environment.'
---
Learn how to connect to your Postgres database from a serverless environment. The driver you use depends on which runtime your code runs in.
[supabase-js](/docs/reference/javascript/introduction) is an isomorphic JavaScript client that uses the [auto-generated REST API](/docs/guides/api), so it works in any environment that supports HTTPS connections. This API has a built-in [connection pooler](/docs/guides/database/connecting-to-postgres/pooling-and-limits#how-connection-pooling-works) and can serve thousands of simultaneous requests, which suits serverless workloads.
If you connect with a Postgres client instead, use the [shared pooler in transaction mode](/docs/guides/database/connecting-to-postgres#pooler-transaction-mode), then [configure your client](/docs/guides/database/connecting-to-postgres#configure-your-client) for pool size, prepared statements, and SSL. Those three settings are what most serverless connection problems come down to.
## Vercel Edge Functions
Vercel's [Edge runtime](https://vercel.com/docs/functions/runtimes/edge-runtime) runs on the [V8 engine](https://v8.dev/) and exposes a limited set of Web Standard APIs.
Start from a deploy template, or configure the connection yourself.
### Quickstart
Choose one of these Vercel Deploy Templates. They use the [Vercel Deploy Integration](https://vercel.com/integrations/supabase) to configure your connection strings as environment variables on your Vercel project.
<div>
<div className="grid grid-cols-12 gap-6 not-prose">
<Link
href="https://supabase.link/nextjs-with-supabase-starter"
className="col-span-12 md:col-span-6 xl:col-span-4"
passHref
>
<GlassPanel title="supabase-js" hasLightIcon={true} showIconBg={true}>
A Next.js App Router template configured with cookie-based auth using Supabase, TypeScript
and Tailwind CSS.
</GlassPanel>
</Link>
<Link
href="https://supabase.link/nextjs-supabase-kysely"
className="col-span-12 md:col-span-6 xl:col-span-4"
passHref
>
<GlassPanel title="Kysely" hasLightIcon={true} showIconBg={true}>
Basic Next.js template that uses Supabase as the database and Kysely as the query builder.
</GlassPanel>
</Link>
</div>
</div>
### Manual configuration
1. In the Supabase Dashboard, click [Connect](/dashboard/project/_?showConnect=true&method=transaction) and copy the URI from the **Transaction pooler** section.
2. Replace the password placeholder with your database password.
3. Add the suffix `?workaround=supabase-pooler.vercel` to the URI.
4. Save the result as the `POSTGRES_URL` environment variable.
```txt .env.local
POSTGRES_URL="postgresql://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@[POOLER-HOST]:6543/postgres?workaround=supabase-pooler.vercel"
```
<Tabs scrollable defaultActiveId="drizzle" type="underlined" size="small">
<TabPanel id="drizzle" label="Drizzle">
```ts lib/drizzle.ts
import { sql } from '@vercel/postgres'
import { InferInsertModel, InferSelectModel } from 'drizzle-orm'
import { pgTable, serial, text, timestamp, uniqueIndex } from 'drizzle-orm/pg-core'
import { drizzle } from 'drizzle-orm/vercel-postgres'
export const UsersTable = pgTable(
'users',
{
id: serial('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull(),
image: text('image').notNull(),
createdAt: timestamp('createdAt').defaultNow().notNull(),
},
(users) => {
return {
uniqueIdx: uniqueIndex('unique_idx').on(users.email),
}
}
)
export type User = InferSelectModel<typeof UsersTable>
export type NewUser = InferInsertModel<typeof UsersTable>
// Connect to Vercel Postgres
export const db = drizzle(sql)
```
</TabPanel>
<TabPanel id="kysely" label="Kysely">
```ts lib/kysely.ts
import { createKysely } from '@vercel/postgres-kysely'
import { ColumnType, Generated } from 'kysely'
interface UserTable {
// Columns that are generated by the database should be marked
// using the `Generated` type. This way they are automatically
// made optional in inserts and updates.
id: Generated<number>
name: string
email: string
image: string
// You can specify a different type for each operation (select, insert and
// update) using the `ColumnType<SelectType, InsertType, UpdateType>`
// wrapper. Here we define a column `createdAt` that is selected as
// a `Date`, can optionally be provided as a `string` in inserts and
// can never be updated:
createdAt: ColumnType<Date, string | undefined, never>
}
// Keys of this interface are table names.
export interface Database {
users: UserTable
}
export const db = createKysely<Database>()
export { sql } from 'kysely'
```
</TabPanel>
</Tabs>
## Cloudflare Workers
Cloudflare's Workers runtime also uses the [V8 engine](https://v8.dev/), but it provides polyfills for a subset of Node.js APIs and the [TCP Sockets API](https://developers.cloudflare.com/workers/runtime-apis/tcp-sockets/). That gives you three options:
### Drivers [#cloudflare-workers-drivers]
- [supabase-js](https://developers.cloudflare.com/workers/databases/native-integrations/supabase/)
- [Postgres.js](https://github.com/porsager/postgres?tab=readme-ov-file#cloudflare-workers-support)
- [node-postgres](https://developers.cloudflare.com/workers/tutorials/postgres/)
## Supabase Edge Functions
Supabase Edge Functions use the [Deno runtime](https://deno.com/), which has native support for TCP connections. You can choose any of these clients:
### Drivers [#supabase-edge-functions-drivers]
- [supabase-js](/docs/guides/functions/connect-to-postgres#using-supabase-js)
- [Deno Postgres driver](/docs/guides/functions/connect-to-postgres#using-a-postgres-client)
- [Postgres.js](https://github.com/porsager/postgres)
- [Drizzle](/docs/guides/functions/connect-to-postgres#using-drizzle)