Skip to main content
Prisma Documentation Docs

Search documentation

Type to search this documentation.

On this pageOverview

Cloudflare Workers

Yes, Prisma Postgres works on Cloudflare Workers.

Standard PostgreSQL clients (like pg or postgres.js) use TCP connections, and Cloudflare Workers doesn't support TCP by default. That's why most Postgres databases can't be accessed directly from Workers. There are two ways around it with Prisma Postgres:

  1. Node.js compatibility mode: add the nodejs_compat flag to your wrangler.jsonc and Prisma ORM can use TCP via Cloudflare's Node.js TCP API. That's what this guide does.
  2. Serverless HTTP driver: the @prisma/ppg driver connects over HTTP instead of TCP, so no compatibility flag is needed.

This guide uses the nodejs_compat approach. Prisma Postgres handles connection pooling, so you don't have to worry about Workers spinning up a new connection per request.

You can find a complete example on GitHub.

Create a new Cloudflare Workers project:

title="bun"
bunx create-cloudflare prisma-cloudflare-worker --type hello-world --ts=true --git=true --deploy=false
pnpm
pnpm create cloudflare prisma-cloudflare-worker --type=hello-world --ts=true --git=true --deploy=false
yarn
yarn create cloudflare prisma-cloudflare-worker --type=hello-world --ts=true --git=true --deploy=false
npm
npm create cloudflare@latest prisma-cloudflare-worker -- --type=hello-world --ts=true --git=true --deploy=false

Navigate into the newly created project directory:

cd prisma-cloudflare-worker

To get started with Prisma, you'll need to install a few dependencies:

title="bun"
bun add prisma@prev dotenv-cli @types/pg --dev
pnpm
pnpm add prisma@prev dotenv-cli @types/pg --save-dev
yarn
yarn add prisma@prev dotenv-cli @types/pg --dev
npm
npm install prisma@prev dotenv-cli @types/pg --save-dev
bun add @prisma/client@7 @prisma/adapter-pg dotenv pg
Bash
pnpm add @prisma/client@7 @prisma/adapter-pg dotenv pg
Bash
yarn add @prisma/client@7 @prisma/adapter-pg dotenv pg
Bash
npm install @prisma/client@7 @prisma/adapter-pg dotenv pg

[!NOTE] If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of @prisma/adapter-pg. For more information, see Database drivers.

Once installed, initialize Prisma in your project:

Once installed, initialize Prisma in your project:

bunx --bun prisma init
Bash
pnpm prisma init
Bash
yarn prisma init
Bash
npx prisma init

[!NOTE] prisma init creates the Prisma scaffolding and a local DATABASE_URL. In the next step, you will create a Prisma Postgres database and replace that value with a direct postgres://... connection string.

This will create:

  • A prisma/ directory with a schema.prisma file
  • A prisma.config.ts file with your Prisma configuration
  • A .env file with a local DATABASE_URL already set

Create a Prisma Postgres database and replace the generated DATABASE_URL in your .env file with the postgres://... connection string from the CLI output:

This will create:

  • A prisma/ directory with a schema.prisma file
  • A prisma.config.ts file with your Prisma configuration
  • A .env file with a local DATABASE_URL already set

Create a Prisma Postgres database and replace the generated DATABASE_URL in your .env file with the postgres://... connection string from the CLI output:

title="bun"
bunx create-db
pnpm
pnpm dlx create-db
yarn
yarn dlx create-db
npm
npx create-db

Cloudflare Workers needs Node.js compatibility enabled to work with Prisma. Add the nodejs_compat compatibility flag to your wrangler.jsonc:

title="wrangler.jsonc"
{

  "name": "prisma-cloudflare-worker",

  "main": "src/index.ts",

  "compatibility_flags": ["nodejs_compat"], 

  "compatibility_date": "2024-01-01"

}

In the prisma/schema.prisma file, add the following User model and set the runtime to cloudflare:

title="prisma/schema.prisma"
generator client {

  provider = "prisma-client"

  runtime  = "cloudflare"

  output   = "../src/generated/prisma"

}

datasource db {

  provider = "postgresql"

}

model User { 

  id    Int    @id @default(autoincrement()) 

  email String

  name  String

} 

This creates a User model with an auto-incrementing ID, email, and name.

Add the following scripts to your package.json to work with Prisma in the Cloudflare Workers environment:

title="package.json"
{

  "scripts": {

    "migrate": "prisma migrate dev", 

    "generate": "prisma generate", 

    "studio": "prisma studio"

    // ... existing scripts

  }

}

Now, run the following command to create the database tables:

title="bun"
bun run migrate
pnpm
pnpm run migrate
yarn
yarn migrate
npm
npm run migrate

When prompted, name your migration (e.g., init).

Then generate the Prisma Client:

title="bun"
bun run generate
pnpm
pnpm run generate
yarn
yarn generate
npm
npm run generate

This generates the Prisma Client in the src/generated/prisma/client directory.

At the top of src/index.ts, import the generated Prisma Client and the PostgreSQL adapter, and define the Env interface for type-safe environment variables:

title="src/index.ts"
import { PrismaClient } from "./generated/prisma/client"; 

import { PrismaPg } from "@prisma/adapter-pg"; 

export interface Env {

  DATABASE_URL: string; 

} 

export default {

  async fetch(request, env, ctx): Promise<Response> {

    return new Response("Hello World!");

  },

} satisfies ExportedHandler<Env>;

Add a check to filter out favicon requests, which browsers automatically send and can clutter your logs:

title="src/index.ts"
import { PrismaClient } from "./generated/prisma/client";

import { PrismaPg } from "@prisma/adapter-pg";

export interface Env {

  DATABASE_URL: string;

}

export default {

  async fetch(request, env, ctx): Promise<Response> {

    const path = new URL(request.url).pathname; 

    if (path === "/favicon.ico")

      return new Response("Resource not found", {

        status: 404, 

        headers: {

          "Content-Type": "text/plain", 

        }, 

      }); 

    return new Response("Hello World!");

  },

} satisfies ExportedHandler<Env>;

Create a database adapter and initialize Prisma Client with it. This must be done for each request in edge environments:

title="src/index.ts"
import { PrismaClient } from "./generated/prisma/client";

import { PrismaPg } from "@prisma/adapter-pg";

export interface Env {

  DATABASE_URL: string;

}

export default {

  async fetch(request, env, ctx): Promise<Response> {

    const path = new URL(request.url).pathname;

    if (path === "/favicon.ico")

      return new Response("Resource not found", {

        status: 404,

        headers: {

          "Content-Type": "text/plain",

        },

      });

    const adapter = new PrismaPg({

      connectionString: env.DATABASE_URL, 

    }); 

    const prisma = new PrismaClient({

      adapter, 

    }); 

    return new Response("Hello World!");

  },

} satisfies ExportedHandler<Env>;

Now use Prisma Client to create a new user and count the total number of users:

title="src/index.ts"
import { PrismaClient } from "./generated/prisma/client";

import { PrismaPg } from "@prisma/adapter-pg";

export interface Env {

  DATABASE_URL: string;

}

export default {

  async fetch(request, env, ctx): Promise<Response> {

    const path = new URL(request.url).pathname;

    if (path === "/favicon.ico")

      return new Response("Resource not found", {

        status: 404,

        headers: {

          "Content-Type": "text/plain",

        },

      });

    const adapter = new PrismaPg({

      connectionString: env.DATABASE_URL,

    });

    const prisma = new PrismaClient({

      adapter,

    });

    const user = await prisma.user.create({

      data: {

        email: `Prisma-Postgres-User-${Math.ceil(Math.random() * 1000)}@gmail.com`, 

        name: "Jon Doe", 

      }, 

    }); 

    const userCount = await prisma.user.count(); 

    return new Response("Hello World!");

  },

} satisfies ExportedHandler<Env>;

Finally, update the response to display the newly created user and the total user count:

title="src/index.ts"
import { PrismaClient } from "./generated/prisma/client";import { PrismaPg } from "@prisma/adapter-pg";export interface Env {  DATABASE_URL: string;}export default {  async fetch(request, env, ctx): Promise<Response> {    const path = new URL(request.url).pathname;    if (path === "/favicon.ico")      return new Response("Resource not found", {        status: 404,        headers: {          "Content-Type": "text/plain",        },      });    const adapter = new PrismaPg({      connectionString: env.DATABASE_URL,    });    const prisma = new PrismaClient({      adapter,    });    const user = await prisma.user.create({      data: {        email: `Prisma-Postgres-User-${Math.ceil(Math.random() * 1000)}@gmail.com`,        name: "Jon Doe",      },    });    const userCount = await prisma.user.count();    return new Response(`\       Created new user: ${user.name} (${user.email}).      Number of users in the database: ${userCount}.    `);   },} satisfies ExportedHandler<Env>;

First, generate the TypeScript types for your Worker environment:

title="bun"
bunx wrangler types --no-strict-vars
pnpm
pnpm dlx wrangler types --no-strict-vars
yarn
yarn dlx wrangler types --no-strict-vars
npm
npx wrangler types --no-strict-vars

Then start the development server:

bun run dev
Bash
pnpm run dev
Bash
yarn dev
Bash
npm run dev

Open http://localhost:8787 in your browser. Each time you refresh the page, a new user will be created. You should see output similar to:

Created new user: Jon Doe (Prisma-Postgres-User-742@gmail.com).
Number of users in the database: 5.

Open http://localhost:8787 in your browser. Each time you refresh the page, a new user will be created. You should see output similar to:

Created new user: Jon Doe (Prisma-Postgres-User-742@gmail.com).

Number of users in the database: 5.

To view your database contents, open Prisma Studio:

title="bun"
bun run studio
pnpm
pnpm run studio
yarn
yarn studio
npm
npm run studio

This will open a browser window where you can view and edit your User table data.

Before deploying, you need to set your DATABASE_URL as a secret in Cloudflare Workers. This keeps your database connection string secure in production.

title="bun"
bunx wrangler secret put DATABASE_URL
pnpm
pnpm dlx wrangler secret put DATABASE_URL
yarn
yarn dlx wrangler secret put DATABASE_URL
npm
npx wrangler secret put DATABASE_URL

When prompted, paste your database connection string from the .env file.

Deploy your Worker to Cloudflare:

bun run deploy
Bash
pnpm run deploy
Bash
yarn deploy
Bash
npm run deploy

Once deployed, Cloudflare will provide you with a URL where your Worker is live (e.g., https://prisma-postgres-worker.your-subdomain.workers.dev).

Visit the URL in your browser, and you'll see your Worker creating users in production!

Once deployed, Cloudflare will provide you with a URL where your Worker is live (e.g., https://prisma-postgres-worker.your-subdomain.workers.dev).

Visit the URL in your browser, and you'll see your Worker creating users in production!

Now that you have a working Cloudflare Workers app connected to a Prisma Postgres database, you can:

Suggest an edit

Propose a replacement for this page. The site team reviews it before applying any changes.

Export
Documentation menu