apps/docs/content/docs/guides/deployment/cloudflare-workers.mdx
Prisma ORM provides type-safe database access, and Cloudflare Workers enables you to deploy serverless code at the edge. Together with Prisma Postgres, you get a globally distributed backend with low-latency database access.
In this guide, you'll learn to integrate Prisma ORM with a Prisma Postgres database in a Cloudflare Workers project. You can find a complete example of this guide on GitHub.
Create a new Cloudflare Workers project:
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:
npm install prisma dotenv-cli @types/pg --save-dev
npm install @prisma/client @prisma/adapter-pg dotenv pg
:::info
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:
npx prisma init --db
:::info You'll need to answer a few questions while setting up your Prisma Postgres database. Select the region closest to your location and a memorable name for your database like "My Cloudflare Workers Project" :::
This will create:
prisma/ directory with a schema.prisma fileprisma.config.ts file with your Prisma configuration.env file with a DATABASE_URL already setCloudflare Workers needs Node.js compatibility enabled to work with Prisma. Add the nodejs_compat compatibility flag to your wrangler.jsonc:
{
"name": "prisma-cloudflare-worker",
"main": "src/index.ts",
"compatibility_flags": ["nodejs_compat"], // [!code ++]
"compatibility_date": "2024-01-01"
}
In the prisma/schema.prisma file, add the following User model and set the runtime to cloudflare:
generator client {
provider = "prisma-client"
runtime = "cloudflare" // [!code ++]
output = "../src/generated/prisma"
}
datasource db {
provider = "postgresql"
}
model User { // [!code ++]
id Int @id @default(autoincrement()) // [!code ++]
email String // [!code ++]
name String // [!code ++]
} // [!code ++]
:::note
Both the cloudflare and workerd runtimes are supported. Read more about runtimes here.
:::
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:
{
"scripts": {
"migrate": "prisma migrate dev", // [!code ++]
"generate": "prisma generate", // [!code ++]
"studio": "prisma studio" // [!code ++]
// ... existing scripts
}
}
Now, run the following command to create the database tables:
npm run migrate
When prompted, name your migration (e.g., init).
Then generate the Prisma Client:
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:
import { PrismaClient } from "./generated/prisma/client"; // [!code ++]
import { PrismaPg } from "@prisma/adapter-pg"; // [!code ++]
// [!code ++]
export interface Env {
// [!code ++]
DATABASE_URL: string; // [!code ++]
} // [!code ++]
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:
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; // [!code ++]
if (path === "/favicon.ico")
// [!code ++]
return new Response("Resource not found", {
// [!code ++]
status: 404, // [!code ++]
headers: {
// [!code ++]
"Content-Type": "text/plain", // [!code ++]
}, // [!code ++]
}); // [!code ++]
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:
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({
// [!code ++]
connectionString: env.DATABASE_URL, // [!code ++]
}); // [!code ++]
// [!code ++]
const prisma = new PrismaClient({
// [!code ++]
adapter, // [!code ++]
}); // [!code ++]
return new Response("Hello World!");
},
} satisfies ExportedHandler<Env>;
:::warning
In edge environments like Cloudflare Workers, you create a new Prisma Client instance per request. This is different from long-running Node.js servers where you typically instantiate a single client and reuse it.
:::
Now use Prisma Client to create a new user and count the total number of users:
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({
// [!code ++]
data: {
// [!code ++]
email: `Prisma-Postgres-User-${Math.ceil(Math.random() * 1000)}@gmail.com`, // [!code ++]
name: "Jon Doe", // [!code ++]
}, // [!code ++]
}); // [!code ++]
// [!code ++]
const userCount = await prisma.user.count(); // [!code ++]
return new Response("Hello World!");
},
} satisfies ExportedHandler<Env>;
Finally, update the response to display the newly created user and the total user count:
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(`\ // [!code highlight]
Created new user: ${user.name} (${user.email}). // [!code highlight]
Number of users in the database: ${userCount}. // [!code highlight]
`); // [!code highlight]
},
} satisfies ExportedHandler<Env>;
First, generate the TypeScript types for your Worker environment:
npx wrangler types --no-strict-vars
Then start the development server:
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 ([email protected]).
Number of users in the database: 5.
To view your database contents, open Prisma Studio:
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.
npx wrangler secret put DATABASE_URL
When prompted, paste your database connection string from the .env file.
Deploy your Worker to Cloudflare:
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!
You've successfully created a Cloudflare Workers application with Prisma ORM connected to a Prisma Postgres database. Your Worker is now running at the edge with low-latency database access.
Now that you have a working Cloudflare Workers app connected to a Prisma Postgres database, you can: