PgBeam Docs

Serverless Driver

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

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:

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 install @neondatabase/serverless
pnpm add @neondatabase/serverless
yarn add @neondatabase/serverless
bun add @neondatabase/serverless

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

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.

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

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

// 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.

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.

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");
db.ts
import { Pool, neonConfig } from "@neondatabase/serverless";
import ws from "ws";

neonConfig.fetchEndpoint = (host) => `https://${host}/sql`;
neonConfig.wsProxy = (host) => `${host}/v2`;
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

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 forOne-shot queries, edge functionsTransactions, session features
ConnectionStateless HTTP requestPersistent WebSocket
Cold startNoneWebSocket handshake + TLS
Transactionssql.transaction([...])BEGIN / COMMIT via client
PipeliningAutomatic (batched in one request)PostgreSQL wire protocol
Max payload~10 MB responseUnlimited streaming

Edge runtime compatibility

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

RuntimeHTTPWebSocketNotes
Vercel Edge FunctionsYesYesBuilt-in WebSocket support
Cloudflare WorkersYesYesBuilt-in WebSocket support
Deno DeployYesYesBuilt-in WebSocket support
BunYesYesBuilt-in WebSocket support
Node.jsYesYesRequires 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.

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);
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

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

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`,
]);

Use standard BEGIN / COMMIT with a dedicated client:

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.

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:

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 and Read Replicas for details.

Common issues

IssueCauseFix
Requests hit api.proxy.pgbeam.app / 404 / wrong projectneonConfig.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 definedNode.js missing WS constructorInstall ws and set neonConfig.webSocketConstructor = ws
fetch failed on HTTP endpointNetwork/firewall blocking HTTPS, or fetchEndpoint not pointed at /sqlVerify the proxy hostname resolves, port 443 is open, and fetchEndpoint is set
Slow cold starts with WebSocketTLS + WS handshake on each invocationUse HTTP transport for stateless queries
connection terminatedIdle timeout exceededUse connection pooling or reconnect on error

Further reading

On this page