# 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
```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
```
#### Raw SQL
```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
```
## 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's Edge runtime, 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`
SELECT * FROM users WHERE email = ${"user@example.com"}
`.collect();
console.log(users[0].name);
```
### Stream results [#stream-results]
Results are returned as `CollectableIterator`. 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`SELECT * FROM users`) {
console.log(user.name);
}
// Or collect all rows into an array
const allUsers = await ppg.sql`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`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 = {
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 = {
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 runtime | ✅ | ✅ |
| 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.