Cloudflare Workers

Learn how to use Prisma ORM in a Cloudflare Workers project

Introduction

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.

Prerequisites

1. Set up your project

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

2. Install and configure Prisma

2.1. Install dependencies

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

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

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:

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

2.2. Enable Node.js compatibility in Cloudflare Workers

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

wrangler.jsonc
{
  "name": "prisma-cloudflare-worker",
  "main": "src/index.ts",
  "compatibility_flags": ["nodejs_compat"], 
  "compatibility_date": "2024-01-01"
}

2.3. Define your Prisma Schema

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

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
} 

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.

2.4. Configure Prisma scripts

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

package.json
{
  "scripts": {
    "migrate": "prisma migrate dev", 
    "generate": "prisma generate", 
    "studio": "prisma studio"
    // ... existing scripts
  }
}

2.5. Run migrations and generate Prisma Client

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.

3. Integrate Prisma into Cloudflare Workers

3.1. Import Prisma Client and configure types

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:

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>;

3.2. Handle favicon requests

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

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>;

3.3. Initialize the Prisma Client

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

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>;

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.

3.4. Create a user and query the database

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

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>;

3.5. Return the results

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

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();

    //edit-start
    return new Response(`\
      Created new user: ${user.name} (${user.email}).
      Number of users in the database: ${userCount}.
    `);
    //edit-end
  },
} satisfies ExportedHandler<Env>;

3.6. Test your Worker locally

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 (Prisma-Postgres-User-742@gmail.com).
Number of users in the database: 5.

3.7. Inspect your data with Prisma Studio

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.

4. Deploy to Cloudflare Workers

4.1. Set your database URL as a secret

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.

4.2. Deploy your Worker

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!

Summary

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.

Next steps

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

  • Add routes to handle different HTTP methods (GET, POST, PUT, DELETE)
  • Extend your Prisma schema with more models and relationships
  • Implement authentication and authorization
  • Use Hono for a more robust routing framework with Cloudflare Workers (see our Hono guide)
  • Enable query caching with Prisma Postgres for better performance

More info

On this page