# Source: https://neon.com/llms/serverless-serverless-driver.txt

# Neon serverless driver

> The Neon serverless driver documentation details the installation, configuration, and usage of the serverless driver for connecting applications to Neon databases, enabling efficient and scalable database interactions in a serverless environment.

## Source

- [Neon serverless driver HTML](https://neon.com/docs/serverless/serverless-driver): The original HTML version of this documentation

The [Neon serverless driver](https://github.com/neondatabase/serverless) is a low-latency Postgres driver for JavaScript and TypeScript that allows you to query data from serverless and edge environments over **HTTP** or **WebSockets** in place of TCP. The driver's low-latency capability is due to [message pipelining and other optimizations](https://neon.com/blog/quicker-serverless-postgres).

   **Important** The Neon serverless driver is now generally available (GA): The GA version of the Neon serverless driver, v1.0.0 and higher, requires Node.js version 19 or higher. It also includes a **breaking change** but only if you're calling the HTTP query template function as a conventional function. For details, please see the [1.0.0 release notes](https://github.com/neondatabase/serverless/pull/149) or read the [blog post](https://neon.com/blog/serverless-driver-ga).

When to query over HTTP vs WebSockets:

- **HTTP**: Querying over an HTTP [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) request is faster for single, non-interactive transactions, also referred to as "one-shot queries". Issuing [multiple queries](https://neon.com/docs/serverless/serverless-driver#issue-multiple-queries-with-the-transaction-function) via a single, non-interactive transaction is also supported. See [Use the driver over HTTP](https://neon.com/docs/serverless/serverless-driver#use-the-driver-over-http).
- **WebSockets**: If you require session or interactive transaction support or compatibility with [node-postgres](https://node-postgres.com/) (the popular **npm** `pg` package), use WebSockets. See [Use the driver over WebSockets](https://neon.com/docs/serverless/serverless-driver#use-the-driver-over-websockets).

   **Tip** AI Rules available: Working with AI coding assistants? Check out our [AI rules for the Neon Serverless Driver](https://neon.com/docs/ai/ai-rules-neon-serverless) to help your AI assistant generate better code for serverless database connections.

## Install the Neon serverless driver

You can install the driver with your preferred JavaScript package manager. For example:

```shell
npm install @neondatabase/serverless
```

The driver includes TypeScript types (the equivalent of `@types/pg`). No additional installation is required.

   **Note**: The Neon serverless driver is also available as a [JavaScript Registry (JSR)](https://jsr.io/docs/introduction) package: [https://jsr.io/@neon/serverless](https://jsr.io/@neon/serverless). The JavaScript Registry (JSR) is a package registry for JavaScript and TypeScript. JSR works with many runtimes (Node.js, Deno, browsers, and more) and is backward compatible with `npm`.

## Configure your Neon database connection

You can obtain a connection string for your database by clicking the **Connect** button on your **Project Dashboard**. Your Neon connection string will look something like this:

```shell
DATABASE_URL=postgresql://[user]:[password]@[neon_hostname]/[dbname]
```

The examples that follow assume that your database connection string is assigned to a `DATABASE_URL` variable in your application's environment file.

## Use the driver over HTTP

The Neon serverless driver uses the [neon](https://github.com/neondatabase/serverless/blob/main/CONFIG.md#neon-function) function for queries over HTTP. The function returns a query function that can only be used as a template function for improved safety against SQL injection vulnerabilities.

For example:

```javascript
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
const id = 1;

// Safe and convenient template function usage
const result = await sql`SELECT * FROM table WHERE id = ${id}`;

// For manually parameterized queries, use the query() function
const result = await sql.query('SELECT * FROM table WHERE id = $1', [id]);

// For interpolating trusted strings (like column or table names), use the unsafe() function
const table = condition ? 'table1' : 'table2'; // known-safe string values
const result = await sql`SELECT * FROM ${sql.unsafe(table)} WHERE id = ${id}`;

// Alternatively, use template literals for known-safe values
const table = condition ? sql`table1` : sql`table2`;
const result = await sql`SELECT * FROM ${table} WHERE id = ${id}`;
```

SQL template queries are fully composable, including those with parameters:

```javascript
const name = 'Olivia';
const limit = 1;
const whereClause = sql`WHERE name = ${name}`;
const limitClause = sql`LIMIT ${limit}`;

// Parameters are numbered appropriately at query time
const result = await sql`SELECT * FROM table ${whereClause} ${limitClause}`;
```

You can use raw SQL queries or tools such as [Drizzle-ORM](https://orm.drizzle.team/docs/quick-postgresql/neon), [kysely](https://github.com/kysely-org/kysely), [Zapatos](https://jawj.github.io/zapatos/), and others for type safety.

Tab: Node.js

```javascript
import { neon } from '@neondatabase/serverless';

const sql = neon(process.env.DATABASE_URL);
const posts = await sql`SELECT * FROM posts WHERE id = ${postId}`;
// or using query() for parameterized queries
const posts = await sql.query('SELECT * FROM posts WHERE id = $1', [postId]);
// `posts` is now [{ id: 12, title: 'My post', ... }] (or undefined)
```

Tab: Drizzle-ORM

```typescript
import { drizzle } from 'drizzle-orm/neon-http';
import { eq } from 'drizzle-orm';
import { neon } from '@neondatabase/serverless';
import { posts } from './schema';

export default async () => {
  const postId = 12;
  const sql = neon(process.env.DATABASE_URL!);
  const db = drizzle(sql);
  const [onePost] = await db.select().from(posts).where(eq(posts.id, postId));
  return new Response(JSON.stringify({ post: onePost }));
};
```

Tab: Vercel Edge Function

```javascript
import { neon } from '@neondatabase/serverless';

export default async (req: Request) => {
  const sql = neon(process.env.DATABASE_URL);
  const posts = await sql`SELECT * FROM posts WHERE id = ${postId}`;
  // or using query() for parameterized queries
  const posts = await sql.query('SELECT * FROM posts WHERE id = $1', [postId]);
  return new Response(JSON.stringify(posts));
}

export const config = {
  runtime: 'edge',
};
```

Tab: Vercel Serverless Function

```ts
import { neon } from '@neondatabase/serverless';
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(request: NextApiRequest, res: NextApiResponse) {
  const sql = neon(process.env.DATABASE_URL!);
  const posts = await sql`SELECT * FROM posts WHERE id = ${postId}`;
  // or using query() for parameterized queries
  const posts = await sql.query('SELECT * FROM posts WHERE id = $1', [postId]);
  return res.status(200).json(posts);
}
```

   **Note**: The maximum request size and response size for queries over HTTP is 64 MB.

### neon function configuration options

The `neon(...)` function returns a query function that can be used as a template function, with additional properties for special cases:

```javascript
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);

// Use as a template function (recommended)
const rows = await sql`SELECT * FROM posts WHERE id = ${postId}`;

// Use query() for manually parameterized queries
const rows = await sql.query('SELECT * FROM posts WHERE id = $1', [postId]);

// Use unsafe() for trusted string interpolation
const table = 'posts'; // trusted value
const rows = await sql`SELECT * FROM ${sql.unsafe(table)} WHERE id = ${postId}`;
```

By default, the query function returns only the rows resulting from the provided SQL query, and it returns them as an array of objects where the keys are column names. For example:

```javascript
const rows = await sql`SELECT * FROM posts WHERE id = ${postId}`;
// -> [{ id: 12, title: "My post", ... }]
```

You can customize the return format using the configuration options `fullResults` and `arrayMode`. These options are available both on the `neon(...)` function and on the query function it returns.

- `arrayMode: boolean`, `false` by default

  The default `arrayMode` value is `false`. When it is true, rows are returned as an array of arrays instead of an array of objects:

  ```javascript
  const sql = neon(process.env.DATABASE_URL, { arrayMode: true });
  const rows = await sql`SELECT * FROM posts WHERE id = ${postId}`;
  // -> [[12, "My post", ...]]
  ```

  Or, with the same effect when using query():

  ```javascript
  const sql = neon(process.env.DATABASE_URL);
  const rows = await sql.query('SELECT * FROM posts WHERE id = $1', [postId], { arrayMode: true });
  // -> [[12, "My post", ...]]
  ```

- `fullResults: boolean`

  The default `fullResults` value is `false`. When it is `true`, additional metadata is returned alongside the result rows, which are then found in the `rows` property of the return value. The metadata matches what would be returned by `node-postgres`:

  ```javascript
  const sql = neon(process.env.DATABASE_URL, { fullResults: true });
  const results = await sql`SELECT * FROM posts WHERE id = ${postId}`;
  /* -> {
    rows: [{ id: 12, title: "My post", ... }],
    fields: [
      { name: "id", dataTypeID: 23, ... },
      { name: "title", dataTypeID: 25, ... },
      ...
    ],
    rowCount: 1,
    rowAsArray: false,
    command: "SELECT"
  } 
  */
  ```

  Or, with the same effect when using query():

  ```javascript
  const sql = neon(process.env.DATABASE_URL);
  const results = await sql.query('SELECT * FROM posts WHERE id = $1', [postId], {
    fullResults: true,
  });
  // -> { ... same as above ... }
  ```

- `fetchOptions: Record<string, any>`

  The `fetchOptions` option can also be passed to either `neon(...)` or the `query` function. This option takes an object that is merged with the options to the `fetch` call.

  For example, to increase the priority of every database `fetch` request:

  ```javascript
  import { neon } from '@neondatabase/serverless';
  const sql = neon(process.env.DATABASE_URL, { fetchOptions: { priority: 'high' } });
  const rows = await sql`SELECT * FROM posts WHERE id = ${postId}`;
  ```

  Or to implement a `fetch` timeout:

  ```javascript
  import { neon } from '@neondatabase/serverless';
  const sql = neon(process.env.DATABASE_URL);
  const abortController = new AbortController();
  const timeout = setTimeout(() => abortController.abort('timed out'), 10000);
  const rows = await sql('SELECT * FROM posts WHERE id = $1', [postId], {
    fetchOptions: { signal: abortController.signal },
  }); // throws an error if no result received within 10s
  clearTimeout(timeout);
  ```

For additional details, see [Options and configuration](https://github.com/neondatabase/serverless/blob/main/CONFIG.md#options-and-configuration).

### Issue multiple queries with the transaction() function

The `transaction(queriesOrFn, options)` function is exposed as a property on the query function. It allows multiple queries to be executed within a single, non-interactive transaction.

The first argument to `transaction()`, `queriesOrFn`, is either an array of queries or a non-async function that receives a query function as its argument and returns an array of queries.

The array-of-queries case looks like this:

```javascript
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
const showLatestN = 10;

const [posts, tags] = await sql.transaction(
  [sql`SELECT * FROM posts ORDER BY posted_at DESC LIMIT ${showLatestN}`, sql`SELECT * FROM tags`],
  {
    isolationLevel: 'RepeatableRead',
    readOnly: true,
  }
);
```

Or as an example of the function case:

```javascript
const [authors, tags] = await neon(process.env.DATABASE_URL).transaction((txn) => [
  txn`SELECT * FROM authors`,
  txn`SELECT * FROM tags`,
]);
```

The optional second argument to `transaction()`, `options`, has the same keys as the options to the ordinary query function — `arrayMode`, `fullResults` and `fetchOptions` — plus three additional keys that concern the transaction configuration. These transaction-related keys are: `isolationMode`, `readOnly` and `deferrable`.

Note that options **cannot** be supplied for individual queries within a transaction. Query and transaction options must instead be passed as the second argument of the `transaction()` function. For example, this `arrayMode` setting is ineffective (and TypeScript won't compile it): `await sql.transaction([sql('SELECT now()', [], { arrayMode: true })])`. Instead, use `await sql.transaction([sql('SELECT now()')], { arrayMode: true })`.

- `isolationMode`

  This option selects a Postgres [transaction isolation mode](https://www.postgresql.org/docs/current/transaction-iso.html). If present, it must be one of `ReadUncommitted`, `ReadCommitted`, `RepeatableRead`, or `Serializable`.

- `readOnly`

  If `true`, this option ensures that a `READ ONLY` transaction is used to execute the queries passed. This is a boolean option. The default value is `false`.

- `deferrable`

  If `true` (and if `readOnly` is also `true`, and `isolationMode` is `Serializable`), this option ensures that a `DEFERRABLE` transaction is used to execute the queries passed. This is a boolean option. The default value is `false`.

For additional details, see [transaction(...) function](https://github.com/neondatabase/serverless/blob/main/CONFIG.md#transaction-function).

### Using transactions with JWT self-verification

When using Row-Level Security (RLS) to secure backend SQL with the Neon serverless driver, you may need to set JWT claims within a transaction context. This is particularly useful for custom JWT verification flows in backend APIs, where you want to ensure user-specific access to rows according to RLS policies.

Here's an example of how to use the `transaction()` function with self-verified JWT claims:

```javascript
import { neon } from '@neondatabase/serverless';

// Example JWT verification function, typically in a separate auth utilitiy file (implement according to your auth provider)
async function verifyJWT(jwtToken, jwksURL) {
  // Your JWT verification logic here
  // This should return the decoded payload
  return { payload: { sub: 'user123', email: 'user@example.com' } };
}

const sql = neon(process.env.DATABASE_URL);

// Get JWT token from request headers or context
const jwtToken = req.headers.authorization?.replace('Bearer ', '');
const jwksURL = process.env.JWKS_URL; // Your JWKS endpoint

// Verify the JWT and extract claims
const { payload } = await verifyJWT(jwtToken, jwksURL);
const claims = JSON.stringify(payload);

// Use transaction to set JWT claims and query data
const [, my_table] = await sql.transaction([
  sql`SELECT set_config('request.jwt.claims', ${claims}, true)`,
  sql`SELECT * FROM my_table`,
]);
```

   **Important**: When using JWT self-verification with RLS, ensure your database connection string uses a role that does **not** have the `BYPASSRLS` attribute. Avoid using the `neondb_owner` role in your connection string, as it bypasses Row-Level Security policies.

This pattern allows you to:

- Verify JWTs using your own authentication logic
- Set the JWT claims in the database session context
- Access JWT claims in your RLS policies
- Execute multiple queries within a single transaction while maintaining the auth context

## Use the driver over WebSockets

The Neon serverless driver supports the [Pool and Client](https://github.com/neondatabase/serverless?tab=readme-ov-file#pool-and-client) constructors for querying over WebSockets.

The `Pool` and `Client` constructors, provide session and transaction support, as well as `node-postgres` compatibility. You can find the API guide for the `Pool` and `Client` constructors in the [node-postgres](https://node-postgres.com/) documentation.

Consider using the driver with `Pool` or `Client` in the following scenarios:

- You already use `node-postgres` in your code base and would like to migrate to using `@neondatabase/serverless`.
- You are writing a new code base and want to use a package that expects a `node-postgres-compatible` driver.
- Your backend service uses sessions / interactive transactions with multiple queries per connection.

You can use the Neon serverless driver in the same way you would use `node-postgres` with `Pool` and `Client`. Where you usually import `pg`, import `@neondatabase/serverless` instead.

Tab: Node.js

```javascript
import { Pool } from '@neondatabase/serverless';

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const posts = await pool.query('SELECT * FROM posts WHERE id =$1', [postId]);
pool.end();
```

Tab: Prisma

```typescript
import { Pool, neonConfig } from '@neondatabase/serverless';
import { PrismaNeon } from '@prisma/adapter-neon';
import { PrismaClient } from '@prisma/client';
import dotenv from 'dotenv';
import ws from 'ws';

dotenv.config();
neonConfig.webSocketConstructor = ws;
const connectionString = `${process.env.DATABASE_URL}`;

const pool = new Pool({ connectionString });
const adapter = new PrismaNeon(pool);
const prisma = new PrismaClient({ adapter });

async function main() {
  const posts = await prisma.post.findMany();
}

main();
```

Tab: Drizzle-ORM

```typescript
import { drizzle } from 'drizzle-orm/neon-serverless';
import { eq } from 'drizzle-orm';
import { Pool } from '@neondatabase/serverless';
import { posts } from './schema';

export default async () => {
  const postId = 12;
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });
  const db = drizzle(pool);
  const [onePost] = await db.select().from(posts).where(eq(posts.id, postId));

  ctx.waitUntil(pool.end());

  return new Response(JSON.stringify({ post: onePost }));
};
```

Tab: Vercel Edge Function

```javascript
import { Pool } from '@neondatabase/serverless';

export default async (req: Request, ctx: any) => {
  const pool = new Pool({connectionString: process.env.DATABASE_URL});
  await pool.connect();

  const posts = await pool.query('SELECT * FROM posts WHERE id = $1', [postId]);

  ctx.waitUntil(pool.end());

  return new Response(JSON.stringify(post), {
    headers: { 'content-type': 'application/json' }
  });
}

export const config = {
  runtime: 'edge',
};
```

Tab: Vercel Serverless Function

```ts
import { Pool } from '@neondatabase/serverless';
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(request: NextApiRequest, res: NextApiResponse) {
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });
  const posts = await pool.query('SELECT * FROM posts WHERE id = $1', [postId]);

  await pool.end();

  return res.status(500).send(post);
}
```

### Pool and Client usage notes

- In Node.js and some other environments, there's no built-in WebSocket support. In these cases, supply a WebSocket constructor function.

  ```javascript
  import { Pool, neonConfig } from '@neondatabase/serverless';
  import ws from 'ws';
  neonConfig.webSocketConstructor = ws;
  ```

- In serverless environments such as Vercel Edge Functions or Cloudflare Workers, WebSocket connections can't outlive a single request. That means `Pool` or `Client` objects must be connected, used and closed within a single request handler. Don't create them outside a request handler; don't create them in one handler and try to reuse them in another; and to avoid exhausting available connections, don't forget to close them.

For examples that demonstrate these points, see [Pool and Client](https://github.com/neondatabase/serverless?tab=readme-ov-file#pool-and-client).

### Advanced configuration options

For advanced configuration options, see [neonConfig configuration](https://github.com/neondatabase/serverless/blob/main/CONFIG.md#neonconfig-configuration), in the Neon serverless driver GitHub readme.

## Developing locally with the Neon serverless driver

The Neon serverless driver enables you to query data over **HTTP** or **WebSockets** instead of TCP, even though Postgres does not natively support these connection methods. To use the Neon serverless driver locally, you must run a local instance of Neon's proxy and configure it to connect to your local Postgres database.

For a step-by-step guide to setting up a local environment, refer to this community guide: [Local Development with Neon](https://neon.com/guides/local-development-with-neon). The guide demonstrates how to use a [community-developed Docker Compose file](https://github.com/TimoWilhelm/local-neon-http-proxy) to configure a local Postgres database and a Neon proxy service. This setup allows connections over both WebSockets and HTTP.

## Example applications

Explore the example applications that use the Neon serverless driver.

### UNESCO World Heritage sites app

Neon provides an example application to help you get started with the Neon serverless driver. The application generates a `JSON` listing of the 10 nearest UNESCO World Heritage sites using IP geolocation (data copyright © 1992 – 2022 UNESCO/World Heritage Centre).



There are different implementations of the application to choose from.

- [Raw SQL + Vercel Edge Functions](https://github.com/neondatabase/neon-vercel-rawsql): Demonstrates using raw SQL with Neon's serverless driver on Vercel Edge Functions
- [Raw SQL via https + Vercel Edge Functions](https://github.com/neondatabase/neon-vercel-http): Demonstrates Neon's serverless driver over HTTP on Vercel Edge Functions
- [Raw SQL + Cloudflare Workers](https://github.com/neondatabase/serverless-cfworker-demo): Demonstrates using the Neon serverless driver on Cloudflare Workers and employs caching for high performance.
- [Kysely + Vercel Edge Functions](https://github.com/neondatabase/neon-vercel-kysely): Demonstrates using kysely and kysely-codegen with Neon's serverless driver on Vercel Edge Functions
- [Zapatos + Vercel Edge Functions](https://github.com/neondatabase/neon-vercel-zapatos): Demonstrates using Zapatos with Neon's serverless driver on Vercel Edge Functions
- [Neon + pgTyped on Vercel Edge Functions](https://github.com/neondatabase/neon-vercel-pgtyped): Demonstrates using pgTyped with Neon's serverless driver on Vercel Edge Functions
- [Neon + Knex on Vercel Edge Functions](https://github.com/neondatabase/neon-vercel-knex): Demonstrates using Knex with Neon's serverless driver on Vercel Edge Functions

### Ping Thing

The Ping Thing application pings a Neon Serverless Postgres database using a Vercel Edge Function and shows the journey your request makes. You can read more about this application in the accompanying blog post: [How to use Postgres at the Edge](https://neon.com/blog/how-to-use-postgres-at-the-edge)

- [Ping Thing](https://github.com/neondatabase/ping-thing): Ping a Neon Serverless Postgres database using a Vercel Edge Function to see the journey your request makes

## Neon serverless driver GitHub repository and changelog

The GitHub repository and [changelog](https://github.com/neondatabase/serverless/blob/main/CHANGELOG.md) for the Neon serverless driver are found [here](https://github.com/neondatabase/serverless).

## References

- [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
- [node-postgres](https://node-postgres.com/)
- [Drizzle-ORM](https://orm.drizzle.team/docs/quick-postgresql/neon)
- [Schema migration with Neon Postgres and Drizzle ORM](https://neon.com/docs/guides/drizzle-migrations)
- [kysely](https://github.com/kysely-org/kysely)
- [Zapatos](https://jawj.github.io/zapatos/)
- [Vercel Edge Functions](https://vercel.com/docs/functions/edge-functions)
- [Cloudflare Workers](https://developers.cloudflare.com/workers/)
- [Use Neon with Cloudflare Workers](https://neon.com/docs/guides/cloudflare-workers)