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