Deploy to Cloudflare Workers & Pages
This page covers everything you need to know to deploy an app with Prisma ORM to a Cloudflare Worker or to Cloudflare Pages.
General considerations when deploying to Cloudflare Workers
This section covers general things you need to be aware of when deploying to Cloudflare Workers or Pages and are using Prisma ORM, regardless of the database provider you use.
Using an edge-compatible driver
When deploying a Cloudflare Worker that uses Prisma ORM, you need to use an edge-compatible driver and its respective driver adapter for Prisma ORM.
The edge-compatible drivers for Cloudflare Workers and Pages are:
- Neon Serverless uses HTTP to access the database
- PlanetScale Serverless uses HTTP to access the database
node-postgres
(pg
) uses Cloudflare'sconnect()
(TCP) to access the database@libsql/client
is used to access Turso databases via HTTP- Cloudflare D1 is used to access D1 databases
There's also work being done on the node-mysql2
driver which will enable access to traditional MySQL databases from Cloudflare Workers and Pages in the future as well.
Note: Prisma Accelerate enables you to access any database from any edge function provider. No edge-compatible driver is necessary.
Setting your database connection URL as an environment variable
First, ensure that the DATABASE_URL
is set as the url
of the datasource
in your Prisma schema:
datasource db {
provider = "postgresql" // this might also be `mysql` or another value depending on your database
url = env("DATABASE_URL")
}
Development
When using your Worker in development, you can configure your database connection via the .dev.vars
file locally.
Assuming you use the DATABASE_URL
environment variable from above, you can set it inside .dev.vars
as follows:
DATABASE_URL="your-database-connection-string"
In the above snippet, your-database-connection-string
is a placeholder that you need to replace with the value of your own connection string, for example:
DATABASE_URL="postgresql://admin:mypassword42@somehost.aws.com:5432/mydb"
Note that the .dev.vars
file is not compatible with .env
files which are typically used by Prisma ORM.
This means that you need to make sure that Prisma ORM gets access to the environment variable when needed, e.g. when running a Prisma CLI command like prisma migrate dev
.
There are several options for achieving this:
- Run your Prisma CLI commands using
dotenv
to specify from where the CLI should read the environment variable, for example:dotenv -e .dev.vars -- npx prisma migrate dev
- Create a script in
package.json
that reads.dev.vars
viadotenv
. You can then executeprisma
commands as follows:npm run env -- npx prisma migrate dev
. Here's a reference for the script:package.json"scripts": { "env": "dotenv -e .dev.vars" }
- Duplicate the
DATABASE_URL
and any other relevant env vars into a new file called.env
which can then be used by Prisma ORM.
Note: If you're using an approach that requires
dotenv
, you need to have thedotenv-cli
package installed. You can do this e.g. by using this command to install the package locally in your project:npm install -D dotenv-cli
.
Production
When deploying your Worker to production, you'll need to set the database connection using the wrangler
CLI:
npx wrangler secret put DATABASE_URL
The command is interactive and will ask you to enter the value for the DATABASE_URL
env var as the next step in the terminal.
Note: This command requires you to be authenticated, and will ask you to log in to your Cloudflare account in case you are not.
Size limits on free accounts
Cloudflare has a size limit of 1 MB for Workers on the free plan. If your application bundle with Prisma ORM exceeds that size, we recommend upgrading to a paid Worker plan or using Prisma Accelerate to deploy your application.
If you're running into this problem with pg
and the @prisma/adapter-pg
package, you can replace the pg
with the custom @prisma/pg-worker
package and use the @prisma/adapter-pg-worker
adapter that belongs to it.
@prisma/pg-worker
is an optimized and lightweight version of pg
that is designed to be used in a Worker. It is a drop-in replacement for pg
and is fully compatible with Prisma ORM.
Deploying a Next.js app to Cloudflare Pages with @cloudflare/next-on-pages
Cloudflare offers an option to run Next.js apps on Cloudflare Pages with @cloudflare/next-on-pages
, see the docs for instructions.
Based on some testing, we found the following:
- You can deploy using the PlanetScale or Neon Serverless Driver.
- Traditional PostgreSQL deployments using
pg
don't work becausepg
itself currently does not work with@cloudflare/next-on-pages
(see here).
Feel free to reach out to us on Discord if you find that anything has changed about this.
Set PRISMA_CLIENT_FORCE_WASM=1
when running locally with node
Some frameworks (e.g. hono) use node
instead of wrangler
for running Workers locally. If you're using such a framework or are running your Worker locally with node
for another reason, you need to set the PRISMA_CLIENT_FORCE_WASM
environment variable:
export PRISMA_CLIENT_FORCE_WASM=1
Database-specific considerations & examples
This section provides database-specific instructions for deploying a Cloudflare Worker with Prisma ORM.
Prerequisites
As a prerequisite for the following section, you need to have a Cloudflare Worker running locally and the Prisma CLI installed.
If you don't have that yet, you can run these commands:
npm create cloudflare@latest prisma-cloudflare-worker-example -- --type hello-world
cd prisma-cloudflare-worker-example
npm install prisma --save-dev
npx prisma init
You'll further need a database instance of your database provider of choice available. Refer to the respective documentation of the provider for setting up that instance.
We'll use the default User
model for the example below:
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
PostgreSQL (traditional)
If you are using a traditional PostgreSQL database that's accessed via TCP and the pg
driver, you need to:
- use the
@prisma/adapter-pg
database adapter (via thedriverAdapters
Preview feature) - set
node_compat = true
inwrangler.toml
(see the Cloudflare docs)
If you are running into a size issue and can't deploy your application because of that, you can use our slimmer variant of the pg
driver package @prisma/pg-worker
and the @prisma/adapter-pg-worker
adapter that belongs to it.
@prisma/pg-worker
is an optimized and lightweight version of pg
that is designed to be used in a Worker. It is a drop-in replacement for pg
and is fully compatible with Prisma ORM.
1. Configure Prisma schema & database connection
Note: If you don't have a project to deploy, follow the instructions in the Prerequisites to bootstrap a basic Cloudflare Worker with Prisma ORM in it.
First, ensure that the database connection is configured properly. In your Prisma schema, set the url
of the datasource
block to the DATABASE_URL
environment variable. You also need to enable the driverAdapters
feature flag:
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
Next, you need to set the DATABASE_URL
environment variable to the value of your database connection string. You'll do this in a file called .dev.vars
used by Cloudflare:
DATABASE_URL="postgresql://admin:mypassword42@somehost.aws.com:5432/mydb"
Because the Prisma CLI by default is only compatible with .env
files, you can adjust your package.json
with the following script that loads the env vars from .dev.vars
. You can then use this script to load the env vars before executing a prisma
command.
Add this script to your package.json
:
{
// ...
"scripts": {
// ....
"env": "dotenv -e .dev.vars"
},
// ...
}
Now you can execute Prisma CLI commands as follows while ensuring that the command has access to the env vars in .dev.vars
:
npm run env -- npx prisma
2. Install dependencies
Next, install the required packages:
npm install @prisma/adapter-pg
npm install pg
npm install @types/pg --save-dev # if you're using TypeScript
3. Set node_compat = true
in wrangler.toml
In your wrangler.toml
file, add the following line:
node_compat = true
Note: For Cloudflare Pages, using
node_compat
is not officially supported. If you want to usepg
in Cloudflare Pages, you can find a workaround here.
4. Migrate your database schema (if applicable)
If you ran npx prisma init
above, you need to migrate your database schema to create the User
table that's defined in your Prisma schema (if you already have all the tables you need in your database, you can skip this step):
npm run env -- npx prisma migrate dev --name init
5. Use Prisma Client in your Worker to send a query to the database
Here is a sample code snippet that you can use to instantiate PrismaClient
and send a query to your database:
import { PrismaClient } from '@prisma/client'
import { PrismaPg } from '@prisma/adapter-pg'
import { Pool } from 'pg'
export default {
async fetch(request, env, ctx) {
const pool = new Pool({ connectionString: env.DATABASE_URL })
const adapter = new PrismaPg(pool)
const prisma = new PrismaClient({ adapter })
const users = await prisma.user.findMany()
const result = JSON.stringify(users)
return new Response(result)
},
}
6. Run the Worker locally
To run the Worker locally, you can run the wrangler dev
command:
npx wrangler dev
7. Set the DATABASE_URL
environment variable and deploy the Worker
To deploy the Worker, you first need to the DATABASE_URL
environment variable via the wrangler
CLI:
npx wrangler secret put DATABASE_URL
The command is interactive and will ask you to enter the value for the DATABASE_URL
env var as the next step in the terminal.
Note: This command requires you to be authenticated, and will ask you to log in to your Cloudflare account in case you are not.
Then you can go ahead then deploy the Worker:
npx wrangler deploy
The command will output the URL where you can access the deployed Worker.
PlanetScale
If you are using a PlanetScale database, you need to:
-
use the
@prisma/adapter-planetscale
database adapter (via thedriverAdapters
Preview feature) -
manually remove the conflicting
cache
field (learn more):export default {
async fetch(request, env, ctx) {
const client = new Client({
url: env.DATABASE_URL,
// see https://github.com/cloudflare/workerd/issues/698
fetch(url, init) {
delete init['cache']
return fetch(url, init)
},
})
const adapter = new PrismaPlanetScale(client)
const prisma = new PrismaClient({ adapter })
// ...
},
}
1. Configure Prisma schema & database connection
Note: If you don't have a project to deploy, follow the instructions in the Prerequisites to bootstrap a basic Cloudflare Worker with Prisma ORM in it.
First, ensure that the database connection is configured properly. In your Prisma schema, set the url
of the datasource
block to the DATABASE_URL
environment variable. You also need to enable the driverAdapters
feature flag:
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma" // required for PlanetScale (as by default foreign keys are disabled)
}
Next, you need to set the DATABASE_URL
environment variable to the value of your database connection string. You'll do this in a file called .dev.vars
used by Cloudflare:
DATABASE_URL="mysql://32qxa2r7hfl3102wrccj:password@us-east.connect.psdb.cloud/demo-cf-worker-ps?sslaccept=strict"
Because the Prisma CLI by default is only compatible with .env
files, you can adjust your package.json
with the following script that loads the env vars from .dev.vars
. You can then use this script to load the env vars before executing a prisma
command.
Add this script to your package.json
:
{
// ...
"scripts": {
// ....
"env": "dotenv -e .dev.vars"
},
// ...
}
Now you can execute Prisma CLI commands as follows while ensuring that the command has access to the env vars in .dev.vars
:
npm run env -- npx prisma
2. Install dependencies
Next, install the required packages:
npm install @prisma/adapter-planetscale
npm install @planetscale/database
3. Migrate your database schema (if applicable)
If you ran npx prisma init
above, you need to migrate your database schema to create the User
table that's defined in your Prisma schema (if you already have all the tables you need in your database, you can skip this step):
npm run env -- npx prisma db push
4. Use Prisma Client in your Worker to send a query to the database
Here is a sample code snippet that you can use to instantiate PrismaClient
and send a query to your database:
import { PrismaClient } from '@prisma/client'
import { PrismaPlanetScale } from '@prisma/adapter-planetscale'
import { Client } from '@planetscale/database'
export default {
async fetch(request, env, ctx) {
const client = new Client({
url: env.DATABASE_URL,
// see https://github.com/cloudflare/workerd/issues/698
fetch(url, init) {
delete init['cache']
return fetch(url, init)
},
})
const adapter = new PrismaPlanetScale(client)
const prisma = new PrismaClient({ adapter })
const users = await prisma.user.findMany()
const result = JSON.stringify(users)
return new Response(result)
},
}
6. Run the Worker locally
To run the Worker locally, you can run the wrangler dev
command:
npx wrangler dev
7. Set the DATABASE_URL
environment variable and deploy the Worker
To deploy the Worker, you first need to the DATABASE_URL
environment variable via the wrangler
CLI:
npx wrangler secret put DATABASE_URL
The command is interactive and will ask you to enter the value for the DATABASE_URL
env var as the next step in the terminal.
Note: This command requires you to be authenticated, and will ask you to log in to your Cloudflare account in case you are not.
Then you can go ahead then deploy the Worker:
npx wrangler deploy
The command will output the URL where you can access the deployed Worker.
Neon
If you are using a Neon database, you need to:
- use the
@prisma/adapter-neon
database adapter (via thedriverAdapters
Preview feature)
1. Configure Prisma schema & database connection
Note: If you don't have a project to deploy, follow the instructions in the Prerequisites to bootstrap a basic Cloudflare Worker with Prisma ORM in it.
First, ensure that the database connection is configured properly. In your Prisma schema, set the url
of the datasource
block to the DATABASE_URL
environment variable. You also need to enable the driverAdapters
feature flag:
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
Next, you need to set the DATABASE_URL
environment variable to the value of your database connection string. You'll do this in a file called .dev.vars
used by Cloudflare:
DATABASE_URL="postgresql://janedoe:password@ep-nameless-pond-a23b1mdz.eu-central-1.aws.neon.tech/neondb?sslmode=require"
Because the Prisma CLI by default is only compatible with .env
files, you can adjust your package.json
with the following script that loads the env vars from .dev.vars
. You can then use this script to load the env vars before executing a prisma
command.
Add this script to your package.json
:
{
// ...
"scripts": {
// ....
"env": "dotenv -e .dev.vars"
},
// ...
}
Now you can execute Prisma CLI commands as follows while ensuring that the command has access to the env vars in .dev.vars
:
npm run env -- npx prisma
2. Install dependencies
Next, install the required packages:
npm install @prisma/adapter-neon
npm install @neondatabase/serverless
3. Migrate your database schema (if applicable)
If you ran npx prisma init
above, you need to migrate your database schema to create the User
table that's defined in your Prisma schema (if you already have all the tables you need in your database, you can skip this step):
npm run env -- npx prisma migrate dev --name init
5. Use Prisma Client in your Worker to send a query to the database
Here is a sample code snippet that you can use to instantiate PrismaClient
and send a query to your database:
import { PrismaClient } from '@prisma/client'
import { PrismaNeon } from '@prisma/adapter-neon'
import { Pool } from '@neondatabase/serverless'
export default {
async fetch(request, env, ctx) {
const neon = new Pool({ connectionString: env.DATABASE_URL })
const adapter = new PrismaNeon(neon)
const prisma = new PrismaClient({ adapter })
const users = await prisma.user.findMany()
const result = JSON.stringify(users)
return new Response(result)
},
}
6. Run the Worker locally
To run the Worker locally, you can run the wrangler dev
command:
npx wrangler dev
7. Set the DATABASE_URL
environment variable and deploy the Worker
To deploy the Worker, you first need to the DATABASE_URL
environment variable via the wrangler
CLI:
npx wrangler secret put DATABASE_URL
The command is interactive and will ask you to enter the value for the DATABASE_URL
env var as the next step in the terminal.
Note: This command requires you to be authenticated, and will ask you to log in to your Cloudflare account in case you are not.
Then you can go ahead then deploy the Worker:
npx wrangler deploy
The command will output the URL where you can access the deployed Worker.
Cloudflare D1
If you are using a D1 database, you need to:
- use the
@prisma/adapter-d1
database adapter (via thedriverAdapters
Preview feature) - set
sqlite
as thedatasource
provider in your Prisma schema - manually generate SQL statements for schema changes using
prisma migrate diff
but execute them using D1's migration system
You can find a deployment-ready example on GitHub.
1. Configure Prisma schema
Note: If you don't have a project to deploy, follow the instructions in the Prerequisites to bootstrap a basic Cloudflare Worker with Prisma ORM in it.
In your Prisma schema, add the driverAdapters
Preview feature to the generator
block and set the provider
of the datasource
to sqlite
. If you just bootstrapped the Prisma schema with prisma init
, also be sure to add the following User
model to it:
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
Note that in this tutorial, you won't need the .env
file since the connection between Prisma ORM and D1 will happen through a binding.
2. Install dependencies
Next, install the required packages:
npm install @prisma/adapter-d1
Also, be sure to use a version of the Wrangler CLI that's above wrangler@^3.39.0
, otherwise the --remote
flag that's used in the next sections won't be available.
3. Set the D1 database connection via a binding
To connect your Workers with the D1 instance, add the following binding to your wrangler.toml
(if you don't have a D1 instance yet, you can create one using the Cloudflare Dashboard or with the wrangler d1 create
command):
name = "prisma-cloudflare-worker-example"
main = "src/index.ts"
compatibility_date = "2024-03-20"
compatibility_flags = ["nodejs_compat"]
[[d1_databases]]
binding = "DB" # i.e. available in your Worker on env.DB
database_name = "__YOUR_D1_DATABASE_NAME__" # to be replaced
database_id = "__YOUR_D1_DATABASE_ID__" # to be replaced
Note that __YOUR_D1_DATABASE_NAME__
and __YOUR_D1_DATABASE_ID__
in the snippet above are placeholders that should be replaced with the database name and ID of your own D1 instance.
If you weren't able to grab this ID from the terminal output, you can also find it in the Cloudflare Dashboard or by running npx wrangler d1 list
and npx wrangler d1 info __YOUR_D1_DATABASE_NAME__
in your terminal.
4. Migrate your database schema (if applicable)
If your Prisma schema only contains the User
model but your D1 database is still empty, you need to make sure that there is a table in D1 that mirrors the structure of the User
model.
D1 comes with its own migration system that lets you manage migration files in your file system. While this is convenient for creating and applying migration files, it doesn't help you identifying the actual SQL statements that you need to put into these migration files. That's where Prisma Migrate comes into play, because you can generate SQL statements for schema changes using the prisma migrate diff
command.
First, create the migrations
directory and initial migration file using the wrangler d1 migrations
command as follows:
npx wrangler d1 migrations create __YOUR_D1_DATABASE_NAME__ create_user_table
Replace __YOUR_D1_DATABASE_NAME__
with the name of your database again and, when prompted, confirm that you want to create the migrations
directory. After having run this command, there should be a new folder called migrations
with a file called 0001_create_user_table.sql
inside of it.
You can now generate the required SQL statement for creating a User
table that can be mapped to the User
model in your the Prisma schema as follows:
npx prisma migrate diff --from-empty --to-schema-datamodel ./prisma/schema.prisma --script --output migrations/0001_create_user_table.sql
Note that the resulting SQL statement is stored in a file in the migrations
directory called 0001_create_user_table.sql
which looks as follows:
-- CreateTable
CREATE TABLE "User" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"email" TEXT NOT NULL,
"name" TEXT
);
-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
You now need to use the wrangler d1 migrations apply
command to send this SQL statement to D1. Note that this command accepts two options:
--local
: Executes the statement against a local version of D1. This local version of D1 is a SQLite database file that'll be located in your project. This approach is useful, when you want to develop and test your Worker on your local machine. Learn more in the Cloudflare docs.--remote
: Executes the statement against your remote version of D1. This version is used by your deployed Cloudflare Workers. Learn more in the Cloudflare docs.
In this tutorial, you'll do both: test the Worker locally and deploy it afterwards. So, you need to run both commands. Open your terminal and paste the following commands:
# For the local database
npx wrangler d1 migrations apply __YOUR_D1_DATABASE_NAME__ --local
# For the remote database
npx wrangler d1 migrations apply __YOUR_D1_DATABASE_NAME__ --remote
As before, you need to replace __YOUR_D1_DATABASE_NAME__
with the name of your D1 database.
Let's also create some dummy data that we can query once the Worker is running. This time, you'll run the SQL statement without storing it in a file:
# For the local database
npx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --command "INSERT INTO \"User\" (\"email\", \"name\") VALUES
('jane@prisma.io', 'Jane Doe (Local)');" --local
# For the remote database
npx wrangler d1 execute __YOUR_D1_DATABASE_NAME__ --command "INSERT INTO \"User\" (\"email\", \"name\") VALUES
('jane@prisma.io', 'Jane Doe (Remote)');" --remote
5. Use Prisma Client in your Worker to send a query to the database
Before adding a Prisma Client query to your Worker, you need to generate Prisma Client with the following command:
npx prisma generate
In order to query your database from the Worker using Prisma ORM, you need to:
- Add the
DB
binding to theEnv
interface. (Alternatively, you can runnpx wrangler types
to generate theEnv
type from the binding in a separate file calledworker-configuration.d.ts
.) - Instantiate
PrismaClient
using thePrismaD1
driver adapter. - Send a query using Prisma Client and return the result.
Open src/index.ts
and replace the entire content with the following:
import { PrismaClient } from '@prisma/client'
import { PrismaD1 } from '@prisma/adapter-d1'
export interface Env {
DB: D1Database
}
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
const adapter = new PrismaD1(env.DB)
const prisma = new PrismaClient({ adapter })
const users = await prisma.user.findMany()
const result = JSON.stringify(users)
return new Response(result)
},
}
6. Run the Worker locally
With the database query in place and Prisma Client generated, you can go ahead and run the Worker locally:
npm run dev
Now you can open your browser at http://localhost:8787
to see the result of the database query:
;[{ id: 1, email: 'jane@prisma.io', name: 'Jane Doe (Local)' }]
7. Set the DATABASE_URL
environment variable and deploy the Worker
To deploy the Worker, run the the following command:
npm run deploy
Your deployed Worker is accessible via https://prisma-d1-example.USERNAME.workers.dev
. If you navigate your browser to that URL, you should see the following data that's queried from your remote D1 database:
;[{ id: 1, email: 'jane@prisma.io', name: 'Jane Doe (Remote)' }]