---
title: "Serverless Driver"
description: "Use @neondatabase/serverless to connect from edge runtimes and serverless functions through PgBeam with HTTP or WebSocket transports."
canonical: "https://pgbeam.com/docs/serverless"
last-updated: "2026-10-29T19:01:20.000Z"
---

# Serverless Driver

> Use @neondatabase/serverless to connect from edge runtimes and serverless functions through PgBeam with HTTP or WebSocket transports.

URL: https://pgbeam.com/docs/serverless

Connect from edge runtimes and serverless functions using the `@neondatabase/serverless` driver. PgBeam supports both the HTTP query endpoint and the WebSocket wire protocol. Your `neon()` / `Pool` call sites and every query stay exactly as they are.

> **One required step: point the driver at PgBeam**
>
> Changing the connection-string host is **not** enough on its own. By default
> `@neondatabase/serverless` derives its endpoint by rewriting the host: it
> replaces the first label with `api.`, so `abc.proxy.pgbeam.app` would resolve
> to `https://api.proxy.pgbeam.app/sql`, dropping the `abc` subdomain PgBeam
> needs to route your project. Point the driver at PgBeam once, globally, with
> `neonConfig` before any query runs:
>
> ```ts title="neon-config.ts (import once at startup)"
> import { neonConfig } from "@neondatabase/serverless";
>
> // HTTP /sql endpoint: keep the project subdomain, append /sql
> neonConfig.fetchEndpoint = (host) => `https://${host}/sql`;
> // WebSocket /v2 endpoint (Pool / Client)
> neonConfig.wsProxy = (host) => `${host}/v2`;
> ```
>
> These two lines are the only addition. Your query call sites do not change. (On Neon's own `*.neon.tech` hosts the defaults work; PgBeam needs the override because its hostnames are not `*.neon.tech`.)

## Setup

### Install the package

**npm**

```bash
npm install @neondatabase/serverless
```

**pnpm**

```bash
pnpm add @neondatabase/serverless
```

**yarn**

```bash
yarn add @neondatabase/serverless
```

**bun**

```bash
bun add @neondatabase/serverless
```

For Node.js environments using WebSocket transport, also install `ws`:

```bash
npm install ws
```

### Point the driver at PgBeam

Set `neonConfig` once, before any query runs (see the warning above for why
this is required). In Node.js, also set the WebSocket constructor.

```ts title="neon-config.ts"
import { neonConfig } from "@neondatabase/serverless";

neonConfig.fetchEndpoint = (host) => `https://${host}/sql`;
neonConfig.wsProxy = (host) => `${host}/v2`;

// Required for the WebSocket Pool/Client paths against PgBeam: PgBeam
// authenticates with SCRAM, but the driver's default pipelining optimistically
// sends a cleartext password before it sees the auth challenge, which hangs the
// connection. Disabling pipelining makes the driver complete the SCRAM handshake.
neonConfig.pipelineConnect = false;

// Node.js only: provide a WebSocket implementation for the Pool/Client paths
// import ws from "ws";
// neonConfig.webSocketConstructor = ws;
```

### HTTP transport: `neon()` tagged template

Best for one-shot queries from edge/serverless functions. Each call is a single
HTTP request. No persistent connection required.

```ts title="query.ts"
import "./neon-config"; // applies neonConfig.fetchEndpoint
import { neon } from "@neondatabase/serverless";

const sql = neon("postgresql://user:pass@abc.proxy.pgbeam.app/mydb");
const rows = await sql`SELECT * FROM users WHERE active = true`;
```

### WebSocket transport: `Pool` / `Client`

Best for interactive transactions or session-level features. Uses the
PostgreSQL wire protocol over WebSocket.

> **Set neonConfig.pipelineConnect = false for WebSocket**
>
> With the driver's default configuration, the WebSocket `Pool` / `Client`
> connection **hangs** against PgBeam. PgBeam authenticates with SCRAM, and the
> driver's default `pipelineConnect: "password"` optimistically pipelines a
> cleartext password before it reads the server's auth challenge, so the SCRAM
> handshake never completes. Set `neonConfig.pipelineConnect = false` (already
> in the `neon-config.ts` above) so the driver waits for the challenge and
> completes SCRAM. The HTTP `neon()` path is unaffected; if you only need
> one-shot queries, it works with just `fetchEndpoint` set.

**Edge runtime**

```ts title="db.ts"
import "./neon-config"; // applies neonConfig.wsProxy
import { Pool } from "@neondatabase/serverless";

const pool = new Pool({
  connectionString: "postgresql://user:pass@abc.proxy.pgbeam.app/mydb",
});
const { rows } = await pool.query("SELECT * FROM users");
```

**Node.js**

```ts title="db.ts"
import { Pool, neonConfig } from "@neondatabase/serverless";
import ws from "ws";

neonConfig.fetchEndpoint = (host) => `https://${host}/sql`;
neonConfig.wsProxy = (host) => `${host}/v2`;
neonConfig.pipelineConnect = false; // required for SCRAM (see callout above)
neonConfig.webSocketConstructor = ws;

const pool = new Pool({
  connectionString: "postgresql://user:pass@abc.proxy.pgbeam.app/mydb",
});
const { rows } = await pool.query("SELECT * FROM users");
```

### Run a test query

```ts
const result = await sql`SELECT 1 AS ok`;
console.log(result); // [{ ok: 1 }]
```

If this returns results, the serverless driver is connected through PgBeam.

## HTTP vs WebSocket

|                  | HTTP (`neon()`)                    | WebSocket (`Pool` / `Client`)  |
| ---------------- | ---------------------------------- | ------------------------------ |
| **Best for**     | One-shot queries, edge functions   | Transactions, session features |
| **Connection**   | Stateless HTTP request             | Persistent WebSocket           |
| **Cold start**   | None                               | WebSocket handshake + TLS      |
| **Transactions** | `sql.transaction([...])`           | `BEGIN` / `COMMIT` via client  |
| **Pipelining**   | Automatic (batched in one request) | PostgreSQL wire protocol       |
| **Max payload**  | \~10 MB response                   | Unlimited streaming            |

## Edge runtime compatibility

The serverless driver works in any runtime with `fetch` (for HTTP) or `WebSocket` (for WS):

| Runtime               | HTTP | WebSocket | Notes                      |
| --------------------- | ---- | --------- | -------------------------- |
| Vercel Edge Functions | Yes  | Yes       | Built-in WebSocket support |
| Cloudflare Workers    | Yes  | Yes       | Built-in WebSocket support |
| Deno Deploy           | Yes  | Yes       | Built-in WebSocket support |
| Bun                   | Yes  | Yes       | Built-in WebSocket support |
| Node.js               | Yes  | Yes       | Requires `ws` package      |

## Drizzle ORM integration

Use the serverless driver adapters with Drizzle for type-safe queries:

The same `neonConfig` setup applies. Drizzle wraps the Neon driver, so once the endpoint is pointed at PgBeam, your Drizzle schema and queries are unchanged.

**HTTP (drizzle-orm/neon-http)**

```ts title="db.ts"
import "./neon-config"; // applies neonConfig.fetchEndpoint
import { neon } from "@neondatabase/serverless";
import { drizzle } from "drizzle-orm/neon-http";

const sql = neon("postgresql://user:pass@abc.proxy.pgbeam.app/mydb");
const db = drizzle(sql);

const users = await db.select().from(usersTable);
```

**WebSocket (drizzle-orm/neon-serverless)**

```ts title="db.ts"
import "./neon-config"; // applies neonConfig.wsProxy (+ webSocketConstructor on Node)
import { Pool } from "@neondatabase/serverless";
import { drizzle } from "drizzle-orm/neon-serverless";

const pool = new Pool({
  connectionString: "postgresql://user:pass@abc.proxy.pgbeam.app/mydb",
});
const db = drizzle(pool);

const users = await db.select().from(usersTable);
```

## Transactions

**HTTP**

Use `sql.transaction()` to run multiple statements in a single HTTP request:

```ts title="HTTP transactions"
import { neon } from "@neondatabase/serverless";

const sql = neon("postgresql://user:pass@abc.proxy.pgbeam.app/mydb");

const results = await sql.transaction([
  sql`UPDATE accounts SET balance = balance - 100 WHERE id = 1`,
  sql`UPDATE accounts SET balance = balance + 100 WHERE id = 2`,
]);
```

**WebSocket**

Use standard `BEGIN` / `COMMIT` with a dedicated client:

```ts title="WebSocket transactions"
import { Pool } from "@neondatabase/serverless";

const pool = new Pool({
  connectionString: "postgresql://user:pass@abc.proxy.pgbeam.app/mydb",
});

const client = await pool.connect();
try {
  await client.query("BEGIN");
  await client.query("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
  await client.query("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
  await client.query("COMMIT");
} catch (e) {
  await client.query("ROLLBACK");
  throw e;
} finally {
  client.release();
}
```

## Data type notes

PgBeam matches the `@neondatabase/serverless` type contract over the HTTP endpoint. In particular, `bigint` (`int8`), `numeric`, and `money` are returned as **strings**, not numbers: a JavaScript `Number` cannot represent integers above 2^53 or arbitrary-precision decimals without silent loss. Wrap them with `BigInt(...)` or a decimal library as needed.

```ts
const [row] = await sql`SELECT 9223372036854775807::bigint AS big`;
row.big; // "9223372036854775807" (string)
BigInt(row.big); // 9223372036854775807n
```

`json` / `jsonb` are parsed into objects, and arrays into JS arrays, exactly as the Neon driver does.

## Caching and replicas

SQL annotations work the same with the serverless driver:

```ts title="Cache and replica annotations"
import { neon } from "@neondatabase/serverless";

const sql = neon("postgresql://user:pass@abc.proxy.pgbeam.app/mydb");

// Cache for 5 minutes
const categories =
  await sql`/* @pgbeam:cache maxAge=300 */ SELECT * FROM categories`;

// Route to read replica
const stats = await sql`/* @pgbeam:replica */ SELECT count(*) FROM orders`;

// Combine both
const products =
  await sql`/* @pgbeam:replica */ /* @pgbeam:cache maxAge=60 */ SELECT * FROM products`;
```

See [Caching](/docs/cache) and [Read Replicas](/docs/replicas) for details.

## Common issues

| Issue                                                     | Cause                                                                                       | Fix                                                                                                             |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| Requests hit `api.proxy.pgbeam.app` / 404 / wrong project | `neonConfig.fetchEndpoint` not set; driver rewrote the host to `api.`                       | Set `neonConfig.fetchEndpoint` so requests target the `/sql` path (see Setup step 2)                            |
| `WebSocket is not defined`                                | Node.js missing WS constructor                                                              | Install `ws` and set `neonConfig.webSocketConstructor = ws`                                                     |
| WebSocket `Pool` / `Client` connects then hangs, no error | Default `pipelineConnect: "password"` pipelines a cleartext password, but PgBeam uses SCRAM | Set `neonConfig.pipelineConnect = false`. If you only need one-shot queries, use the HTTP `neon()` path instead |
| `fetch failed` on HTTP endpoint                           | Network/firewall blocking HTTPS, or `fetchEndpoint` not pointed at `/sql`                   | Verify the proxy hostname resolves, port 443 is open, and `fetchEndpoint` is set                                |
| Slow cold starts with WebSocket                           | TLS + WS handshake on each invocation                                                       | Use HTTP transport for stateless queries                                                                        |
| `connection terminated`                                   | Idle timeout exceeded                                                                       | Use connection pooling or reconnect on error                                                                    |

## Further reading

* [Connection Pooling](/docs/pooling): Pool modes and sizing guidance
* [Caching](/docs/cache): TTL, SWR, cache rules, and SQL annotations
* [Read Replicas](/docs/replicas): Replica setup and routing
* [@neondatabase/serverless on npm](https://www.npmjs.com/package/@neondatabase/serverless): Driver documentation