# Serverless driver (/docs/postgres/database/serverless-driver)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Connect to Prisma Postgres from serverless and edge environments

Location: Postgres > Database > Serverless driver

The Prisma Postgres serverless driver connects to hosted Prisma Postgres databases over HTTP and WebSockets. Use it with Prisma ORM through [`@prisma/adapter-ppg`](https://www.npmjs.com/package/@prisma/adapter-ppg), or query with raw SQL through [`@prisma/ppg`](https://www.npmjs.com/package/@prisma/ppg).

## Choose a connection method [#choose-a-connection-method]

| Runtime                                                              | Recommended connection                              | Package                                                             |
| -------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------- |
| Conventional Node.js or Bun runtime with PostgreSQL TCP support      | [Pooled TCP](https://www.prisma.io/docs/postgres/database/connection-pooling) | `@prisma/adapter-pg` with `pg`                                      |
| Edge or TCP-constrained runtime with `fetch` and `WebSocket` support | Prisma Postgres serverless driver                   | `@prisma/adapter-ppg` with Prisma ORM, or `@prisma/ppg` for raw SQL |

Use the serverless driver when a conventional PostgreSQL TCP driver cannot run. It also supports streaming, pipelined queries, transactions, batch operations, SQL template literals, and custom type handling.

If your application currently uses a hosted `prisma+postgres://` Accelerate connection, follow [Connect to Prisma Postgres without Accelerate](https://www.prisma.io/docs/postgres/database/switch-from-accelerate).

## Get your connection string [#get-your-connection-string]

The serverless driver accepts the direct Prisma Postgres connection-string format:

```text title="Direct connection string"
postgres://identifier:key@db.prisma.io:5432/postgres?sslmode=require
```

It uses this value as a credential, then communicates with Prisma Postgres over HTTP and WebSockets. It does not open a TCP connection.

In the [Prisma Console](https://console.prisma.io/?utm_source=docs\&utm_medium=content\&utm_content=postgres), select your database, choose **Connect to your database**, generate a connection string, and copy the direct value. Do not construct the value by editing another connection string.

If you don't have a Prisma Postgres database, create one using the [`create-db` CLI](https://www.prisma.io/docs/postgres/npx-create-db) tool:

  

#### bun

```bash title="Terminal"
bunx create-db@latest
```

#### pnpm

```bash title="Terminal"
pnpm dlx create-db@latest
```

#### yarn

```bash title="Terminal"
yarn dlx create-db@latest
```

#### npm

```bash title="Terminal"
npx create-db@latest
```

> [!WARNING]
> Keep credentials server-side
> 
> Store `DATABASE_URL` in server-side runtime secrets. Never commit it to source control or include it in code delivered to a browser.

## Installation [#installation]

Install the appropriate package based on your use case:

  

#### With Prisma ORM

  

  <CodeBlockTab value="bun">
    ```bash title="Terminal" 
    bun add @prisma/ppg @prisma/adapter-ppg
    ```

#### pnpm

```bash title="Terminal" 
pnpm add @prisma/ppg @prisma/adapter-ppg
```

#### yarn

```bash title="Terminal" 
yarn add @prisma/ppg @prisma/adapter-ppg
```

#### npm

```bash title="Terminal" 
npm install @prisma/ppg @prisma/adapter-ppg
```
    
  </CodeBlockTab>

#### Raw SQL

  

  <CodeBlockTab value="bun">
    ```bash title="Terminal" 
    bun add @prisma/ppg
    ```

#### pnpm

```bash title="Terminal" 
pnpm add @prisma/ppg
```

#### yarn

```bash title="Terminal" 
yarn add @prisma/ppg
```

#### npm

```bash title="Terminal" 
npm install @prisma/ppg
```
    
  </CodeBlockTab>

## Use with Prisma ORM [#use-with-prisma-orm]

Use the [`PrismaPostgresAdapter`](https://www.npmjs.com/package/@prisma/adapter-ppg) to connect Prisma Client via the serverless driver.

When you generate Prisma Client for an edge runtime, set the generator's [`runtime`](https://www.prisma.io/docs/orm/v7/prisma-schema/overview/generators#field-reference) to the deployment target. For example, use `workerd` for Cloudflare Workers, `vercel-edge` for Vercel Edge Functions, or `deno` for Deno:

```prisma title="prisma/schema.prisma"
generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
  runtime  = "workerd"
}
```

Generate the client, then instantiate it with the serverless driver adapter:

```ts title="src/lib/prisma.ts"
import { PrismaClient } from "../../generated/prisma/client";
import { PrismaPostgresAdapter } from "@prisma/adapter-ppg";

const prisma = new PrismaClient({
  adapter: new PrismaPostgresAdapter({
    connectionString: process.env.DATABASE_URL!,
  }),
});

const users = await prisma.user.findMany();
```

## Query with raw SQL [#query-with-raw-sql]

Use the `prismaPostgres()` high-level API for SQL template literals with automatic parameterization:

```ts title="src/lib/query.ts"
import { prismaPostgres, defaultClientConfig } from "@prisma/ppg";

const ppg = prismaPostgres(defaultClientConfig(process.env.DATABASE_URL!));

type User = { id: number; name: string; email: string };

const users = await ppg.sql<User>`
  SELECT * FROM users WHERE email = ${"user@example.com"}
`.collect();

console.log(users[0].name);
```

### Stream results [#stream-results]

Results are returned as `CollectableIterator<T>`. Stream rows one at a time for constant memory usage, or collect all rows into an array:

```ts title="src/lib/stream.ts"
type User = { id: number; name: string; email: string };

// Stream rows one at a time (constant memory usage)
for await (const user of ppg.sql<User>`SELECT * FROM users`) {
  console.log(user.name);
}

// Or collect all rows into an array
const allUsers = await ppg.sql<User>`SELECT * FROM users`.collect();
```

### Pipeline queries [#pipeline-queries]

Send multiple queries over a single WebSocket connection without waiting for responses. Queries are sent immediately and results arrive in FIFO order:

```ts title="src/lib/pipeline.ts"
import { client, defaultClientConfig } from "@prisma/ppg";

const cl = client(defaultClientConfig(process.env.DATABASE_URL!));
const session = await cl.newSession();

// Send all queries immediately (pipelined)
const [usersResult, ordersResult, productsResult] = await Promise.all([
  session.query("SELECT * FROM users"),
  session.query("SELECT * FROM orders"),
  session.query("SELECT * FROM products"),
]);

session.close();
```

Pipelining reduces network round trips by sending multiple queries before waiting for their responses. The effect on end-to-end latency depends on network conditions and query execution time.

### Parameter streaming [#parameter-streaming]

Parameters over 1KB are automatically streamed without buffering in memory. For large binary parameters, you must use `boundedByteStreamParameter()` which creates a `BoundedByteStreamParameter` object that carries the total byte size, required by the PostgreSQL protocol:

```ts title="src/lib/upload.ts"
import { client, defaultClientConfig, boundedByteStreamParameter, BINARY } from "@prisma/ppg";

const cl = client(defaultClientConfig(process.env.DATABASE_URL!));

// Large binary data (e.g., file content)
const stream = getReadableStream(); // Your ReadableStream source
const totalSize = 1024 * 1024; // Total size must be known in advance

// Create a bounded byte stream parameter
const streamParam = boundedByteStreamParameter(stream, BINARY, totalSize);

// Automatically streamed - constant memory usage
await cl.query("INSERT INTO files (data) VALUES ($1)", streamParam);
```

For `Uint8Array` data, use `byteArrayParameter()`:

```ts title="src/lib/bytes.ts"
import { client, defaultClientConfig, byteArrayParameter, BINARY } from "@prisma/ppg";

const cl = client(defaultClientConfig(process.env.DATABASE_URL!));

const bytes = new Uint8Array([1, 2, 3, 4]);
const param = byteArrayParameter(bytes, BINARY);

await cl.query("INSERT INTO files (data) VALUES ($1)", param);
```

The `boundedByteStreamParameter()` function is provided by the `@prisma/ppg` library and requires the total byte size to be known in advance due to PostgreSQL protocol requirements.

### Transactions and batch operations [#transactions-and-batch-operations]

Transactions automatically handle BEGIN, COMMIT, and ROLLBACK:

```ts title="src/lib/transaction.ts"
const result = await ppg.transaction(async (tx) => {
  await tx.sql.exec`INSERT INTO users (name) VALUES ('Alice')`;
  const users = await tx.sql<User>`SELECT * FROM users WHERE name = 'Alice'`.collect();
  return users[0].name;
});
```

Batch operations execute multiple statements in a single round-trip within an automatic transaction:

```ts title="src/lib/batch.ts"
const [users, affected] = await ppg.batch<[User[], number]>(
  { query: "SELECT * FROM users WHERE id < $1", parameters: [5] },
  { exec: "INSERT INTO users (name) VALUES ($1)", parameters: ["Charlie"] },
);
```

## Type handling [#type-handling]

When using `defaultClientConfig()`, common PostgreSQL types are automatically parsed (`boolean`, `int2`, `int4`, `int8`, `float4`, `float8`, `text`, `varchar`, `json`, `jsonb`, `date`, `timestamp`, `timestamptz`):

```ts title="src/lib/types.ts"
import { prismaPostgres, defaultClientConfig } from "@prisma/ppg";

const ppg = prismaPostgres(defaultClientConfig(process.env.DATABASE_URL!));

// JSON/JSONB automatically parsed
const rows = await ppg.sql<{ data: { key: string } }>`
  SELECT '{"key": "value"}'::jsonb as data
`.collect();
console.log(rows[0].data.key); // "value"

// BigInt parsed to JavaScript BigInt
const bigints = await ppg.sql<{
  big: bigint;
}>`SELECT 9007199254740991::int8 as big`.collect();

// Dates parsed to Date objects
const dates = await ppg.sql<{
  created: Date;
}>`SELECT NOW() as created`.collect();
```

### Custom parsers and serializers [#custom-parsers-and-serializers]

Extend or override the type system with custom parsers (by PostgreSQL OID) and serializers (by type guard):

```ts title="src/lib/custom-parser.ts"
import { client, defaultClientConfig } from "@prisma/ppg";
import type { ValueParser } from "@prisma/ppg";

// Custom parser for UUID type
const uuidParser: ValueParser<string | null> = {
  oid: 2950,
  parse: (value) => (value ? value.toUpperCase() : null),
};

const config = defaultClientConfig(process.env.DATABASE_URL!);
const cl = client({
  ...config,
  parsers: [...(config.parsers ?? []), uuidParser], // Append to defaults
});
```

For custom serializers, place them before defaults so they take precedence:

```ts title="src/lib/custom-serializer.ts"
import { client, defaultClientConfig } from "@prisma/ppg";
import type { ValueSerializer } from "@prisma/ppg";

class Point {
  constructor(
    public x: number,
    public y: number,
  ) {}
}

const pointSerializer: ValueSerializer<Point> = {
  supports: (value: unknown): value is Point => value instanceof Point,
  serialize: (value: Point) => `(${value.x},${value.y})`,
};

const config = defaultClientConfig(process.env.DATABASE_URL!);
const cl = client({
  ...config,
  serializers: [pointSerializer, ...(config.serializers ?? [])], // Your serializer first
});

await cl.query("INSERT INTO locations (point) VALUES ($1)", new Point(10, 20));
```

See the [npm package documentation](https://www.npmjs.com/package/@prisma/ppg) for more details.

## Platform compatibility [#platform-compatibility]

The driver works in server-side environments with `fetch` and `WebSocket` APIs:

| Platform              | HTTP Transport | WebSocket Transport |
| --------------------- | -------------- | ------------------- |
| Cloudflare Workers    | ✅              | ✅                   |
| Vercel Edge Functions | ✅              | ✅                   |
| AWS Lambda            | ✅              | ✅                   |
| Deno Deploy           | ✅              | ✅                   |
| Bun                   | ✅              | ✅                   |
| Node.js 18+           | ✅              | ✅                   |

The package can run in browser environments, but a database connection string is a server credential. Do not use the driver in browser-delivered code. Route browser requests through a server-side endpoint instead.

## Transport modes [#transport-modes]

* **HTTP transport (stateless):** Each query is an independent HTTP request. Best for simple queries and edge functions.
* **WebSocket transport (stateful):** Persistent connection for multiplexed queries. Best for transactions, pipelining, and multiple queries. Create a session with `client().newSession()`.

## API overview [#api-overview]

### `prismaPostgres(config)` [#prismapostgresconfig]

High-level API with SQL template literals, transactions, and batch operations. Recommended for most use cases.

### `client(config)` [#clientconfig]

Low-level API with explicit parameter passing and session management. Use when you need fine-grained control.

See the [npm package](https://www.npmjs.com/package/@prisma/ppg) for complete API documentation.

## Error handling [#error-handling]

Structured error types are provided: `DatabaseError`, `HttpResponseError`, `WebSocketError`, `ValidationError`.

```ts title="src/lib/errors.ts"
import { DatabaseError } from "@prisma/ppg";

try {
  await ppg.sql`SELECT * FROM invalid_table`.collect();
} catch (error) {
  if (error instanceof DatabaseError) {
    console.log(error.code);
  }
}
```

## Connection pooling [#connection-pooling]

The serverless driver uses Prisma Postgres connection pooling by default and requires no additional pool configuration. See the [Prisma Postgres regions](https://www.prisma.io/docs/postgres/faq#what-regions-is-prisma-postgres-available-in).

## Limitations [#limitations]

* Requires a Prisma Postgres instance and does not work with [Local Postgres](https://www.prisma.io/docs/local-development/postgres) databases

## Learn more [#learn-more]

* [`@prisma/ppg` npm package](https://www.npmjs.com/package/@prisma/ppg)
* [prisma/ppg-client GitHub repository](https://github.com/prisma/ppg-client)
* [Prisma Postgres documentation](https://www.prisma.io/docs/postgres)

## Related pages

- [`Backups`](https://www.prisma.io/docs/postgres/database/backups): Manage and restore database backups in Prisma Postgres
- [`Connect to Prisma Postgres without Accelerate`](https://www.prisma.io/docs/postgres/database/switch-from-accelerate): Replace a hosted Prisma Postgres Accelerate connection without moving your database or data
- [`Connecting to your database`](https://www.prisma.io/docs/postgres/database/connecting-to-your-database): Choose the right Prisma Postgres connection string for your runtime, tool, and workload.
- [`Connection pooling`](https://www.prisma.io/docs/postgres/database/connection-pooling): Use Prisma Postgres connection pooling for concurrent application traffic.
- [`Extensions`](https://www.prisma.io/docs/postgres/database/postgres-extensions): Enable and use standard PostgreSQL extensions with Prisma Postgres.