Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 148 additions & 96 deletions examples/prisma.md
Original file line number Diff line number Diff line change
@@ -1,167 +1,202 @@
# Using Prisma on Cloudflare Workers

[Prisma ORM](https://www.prisma.io/docs?utm_source=hono&utm_medium=website&utm_campaign=workers) provides a modern, robust toolkit for interacting with databases. When paired with Hono and Cloudflare Workers, it enables you to deploy high-performance, serverless applications at the edge.
[Prisma ORM](https://www.prisma.io/docs/orm?utm_source=hono&utm_medium=docs&utm_campaign=hono_prisma_example&utm_content=intro_prisma_orm) provides a modern, robust toolkit for interacting with databases. When paired with Hono and Cloudflare Workers, it enables you to deploy high-performance, serverless applications at the edge.

In this guide, we’ll cover two distinct approaches for using Prisma ORM in Hono:

- [**Prisma Postgres**](#using-prisma-postgres):
A managed, serverless PostgreSQL database integration with Prisma. This approach is good for a production-ready setup as Prisma Postgres has built-in connection pooling with zero-cold starts that mitigates [scaling issues in serverless and edge environments](https://www.prisma.io/docs/orm/prisma-client/setup-and-configuration/databases-connections?utm_source=hono&utm_medium=website&utm_campaign=workers#the-serverless-challenge).
Connect to a managed PostgreSQL database with Prisma ORM 8 and the `@prisma/orm-postgres` package. This approach is good for a production-ready setup as Prisma Postgres has built-in connection pooling that mitigates [scaling issues in serverless and edge environments](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/databases-connections?utm_source=hono&utm_medium=docs&utm_campaign=hono_prisma_example&utm_content=intro_serverless_challenge#the-serverless-challenge).

- [**Driver adapters**](#using-prisma-driver-adapters):
An alternative that uses Prisma's flexible driver adapters, allowing you to connect to any database supported by Prisma ORM.
- [**Cloudflare D1**](#using-prisma-driver-adapters):
Connect to a D1 database with Prisma ORM 7 and the `@prisma/adapter-d1` driver adapter.

Both approaches have their own advantages, allowing you to choose the one that best fits your project's needs.

::: tip
The two sections use different Prisma ORM versions on purpose. Prisma ORM 8 is a [release candidate](https://www.prisma.io/docs/orm/release-status?utm_source=hono&utm_medium=docs&utm_campaign=hono_prisma_example&utm_content=intro_release_status) and `npx prisma` now installs it, but it has no D1 package yet, so the D1 section pins `prisma@7` and `@prisma/client@7`.
:::

## Using Prisma Postgres

[Prisma Postgres](https://www.prisma.io/postgres?utm_source=hono&utm_medium=website&utm_campaign=workers) is a managed, serverless PostgreSQL database built on unikernels. It supports features like connection pooling, caching, and query optimization recommendations. A generous free tier is available for initial development, testing, and hobby projects.
[Prisma Postgres](https://www.prisma.io/postgres?utm_source=hono&utm_medium=docs&utm_campaign=hono_prisma_example&utm_content=postgres_prisma_postgres) is a managed PostgreSQL database with built-in connection pooling and a free plan. It is a regular PostgreSQL database behind a connection string, so the steps below also work with any other PostgreSQL server that accepts TLS connections.

### 1. Install Prisma and required dependencies
### 1. Add Prisma ORM to your project

Install Prisma in your Hono project:
Prisma ORM 8 has no `prisma generate` step, no driver adapter package, and no query engine binary. One command installs the Prisma CLI and the `@prisma/orm-postgres` package and creates the files the Worker needs:

```bash
npm i prisma --save-dev
npx prisma@latest orm init --yes --target postgres --authoring psl
```

Install the [Prisma client extension](https://www.npmjs.com/package/@prisma/extension-accelerate) that's required for Prisma Postgres:
::: warning
The `cloudflare-workers` template ships a `pnpm-workspace.yaml`, and `orm init` reads it as a sign that the project uses pnpm. If you use npm, delete that file before running the command; otherwise the packages are installed with pnpm.
:::

```sh
npm i @prisma/extension-accelerate
```
This creates:

Initialize Prisma with an instance of Prisma Postgres:
- `src/prisma/contract.prisma`, where you define your models.
- `src/prisma/contract.json` and `src/prisma/contract.d.ts`, emitted from the contract. The Worker imports both.
- `prisma.config.ts`, which tells the Prisma CLI where the contract is and reads `DATABASE_URL` from `.env`.
- `src/prisma/db.ts`, a module-level client for Node.js scripts. The Worker does not import it; see step 3.

```bash
npx prisma@latest init --db
```
It also adds a `contract:emit` script to `package.json` and updates `tsconfig.json` so the Worker can import the JSON contract. Run the script whenever you edit the contract.

If you don't have a [Prisma Data Platform](https://console.prisma.io/?utm_source=hono&utm_medium=website&utm_campaign=workers) account yet, or if you are not logged in, the command will prompt you to log in using one of the available authentication providers. A browser window will open so you can log in or create an account. Return to the CLI after you have completed this step.
### 2. Connect a database

Once logged in (or if you were already logged in), the CLI will prompt you to select a project name and a database region.
Create a Prisma Postgres database:

Once the command has terminated, it has created:
```bash
npx create-db@latest
```

- A project in your [Platform Console](https://console.prisma.io/?utm_source=hono&utm_medium=website&utm_campaign=workers) containing a Prisma Postgres database instance.
- A `prisma` folder containing `schema.prisma`, where you will define your database schema.
- An `.env` file in the project root, which will contain the Prisma Postgres database url `DATABASE_URL=<your-prisma-postgres-database-url>`.
The command prints a connection string and a claim URL. Open the claim URL to keep the database in your [Prisma Console](https://console.prisma.io/?utm_source=hono&utm_medium=docs&utm_campaign=hono_prisma_example&utm_content=postgres_console_claim) account. Store the connection string in a `.env` file:

Create a `.dev.vars` file and store the `DATABASE_URL` in it:
::: code-group

```bash [.dev.vars]
DATABASE_URL="your_prisma_postgres_url"
```bash [.env]
DATABASE_URL="postgres://..."
```

:::

Keep the `.env` file so that Prisma CLI can access it later on to perform migrations, generate [Prisma Client](https://www.prisma.io/docs/orm/prisma-client?utm_source=hono&utm_medium=website&utm_campaign=workers) or to open [Prisma Studio](https://www.prisma.io/docs/orm/tools/prisma-studio?utm_source=hono&utm_medium=website&utm_campaign=workers).
Both tools read this one file: the Prisma CLI through `prisma.config.ts`, and `wrangler dev` directly, which exposes the value to the Worker as `env.DATABASE_URL`.

### 2. Set up Prisma in your project

Now, open your `schema.prisma` file and define the models for your database schema. For example, you might add an `User` model:
Prisma ORM connects to PostgreSQL over TCP, so enable Node.js compatibility in your Wrangler config:

::: code-group

```ts [schema.prisma]
generator client {
provider = "prisma-client-js"
```jsonc [wrangler.jsonc]
{
"compatibility_flags": ["nodejs_compat"],
}
```

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
```toml [wrangler.toml]
compatibility_flags = ["nodejs_compat"]
```

:::

### 3. Define your models and create the tables

Replace the starter models in `src/prisma/contract.prisma` with your own. For example, a `User` model:

::: code-group

```prisma [src/prisma/contract.prisma]
// use prisma-8

model User {
id Int @id @default(autoincrement())
email String
name String
id Int @id @default(autoincrement())
email String @unique
name String?
}
```

:::

Use [Prisma Migrate](https://www.prisma.io/docs/orm/prisma-migrate) to apply changes to the database:
Emit the contract, then create the tables in your database:

```bash
npx prisma migrate dev
npm run contract:emit
npx prisma db init
```

Create a function like this, which you can use in your project later:
`db init` creates the `User` table and signs the database so it is known to match the emitted contract. For later schema changes during development, use `npx prisma db update`.

### 4. Query the database from Hono

Create one Prisma client per request and close it after the response. Cloudflare Workers do not let a connection opened during one request be used by another, so a client shared at module level works for the first request and hangs the next one. A Hono middleware keeps this in one place:

::: code-group

```ts [prismaFunction.ts]
import { PrismaClient } from '@prisma/client/edge'
import { withAccelerate } from '@prisma/extension-accelerate'
```ts [src/index.ts]
import { Hono } from 'hono'
import postgres from '@prisma/orm-postgres/runtime'
import { contractFromJson } from '@prisma/orm-postgres/static'
import type { Contract } from './prisma/contract.d'
import contractJson from './prisma/contract.json' with { type: 'json' }

const contract = contractFromJson<Contract>(contractJson)

export const getPrisma = (database_url: string) => {
const prisma = new PrismaClient({
datasourceUrl: database_url,
}).$extends(withAccelerate())
return prisma
type Env = {
Bindings: CloudflareBindings
Variables: { db: ReturnType<typeof postgres<Contract>> }
}
```

:::
const app = new Hono<Env>()

Here is an example of how you can use this function in your project:
app.use(async (c, next) => {
const db = postgres({ contract, url: c.env.DATABASE_URL })
c.set('db', db)
await next()
c.executionCtx.waitUntil(db.close())
})

::: code-group
app.get('/users', async (c) => {
const users = await c.var.db.orm.public.User.all()
return c.json(users)
})

```ts [index.ts]
import { Hono } from 'hono'
import { sign, verify } from 'hono/jwt'
import { getPrisma } from '../usefulFun/prismaFun'

// Create the main Hono app
const app = new Hono<{
Bindings: {
DATABASE_URL: string
JWT_SECRET: string
}
Variables: {
userId: string
}
}>()

app.post('/', async (c) => {
// Now you can use it wherever you want
const prisma = getPrisma(c.env.DATABASE_URL)
app.post('/users', async (c) => {
const body = await c.req.json<{ email: string; name?: string }>()
const user = await c.var.db.orm.public.User.create({
email: body.email,
name: body.name ?? null,
})
return c.json(user, 201)
})

export default app
```

:::

If you want to **use your own database with Prisma ORM** and benefit from connection pooling and edge caching, you can enable Prisma Accelerate. Learn more about setting up [Prisma Accelerate](https://www.prisma.io/docs/accelerate/getting-started?utm_source=hono&utm_medium=website&utm_campaign=workers) for your project.
The client does not take the emitted JSON directly, so `contractFromJson` converts it once at module level and every request reuses the result. Models are namespace-qualified on PostgreSQL, so the `User` model is `db.orm.public.User`. `.create(...)` returns the inserted row, database defaults included.

Generate the `CloudflareBindings` type so it includes `DATABASE_URL`, then start the dev server:

```bash
npm run cf-typegen
npm run dev
```

Create a user and read it back:

```bash
curl -X POST http://localhost:8787/users \
-H "content-type: application/json" \
-d '{"email":"alice@prisma.io","name":"Alice"}'
curl http://localhost:8787/users
```

Before deploying, store the connection string as a secret with `npx wrangler secret put DATABASE_URL`, then run `npm run deploy`.

## Using Prisma Driver Adapters

Prisma can be used with the D1 Database via `driverAdapters`. The prerequisites are to install Prisma and integrate Wrangler to bind with your Hono project. This is an example project since all documentation for Hono, Prisma, and D1 Cloudflare is separated and doesn't have exact, precise step-by-step instructions.
Prisma can be used with the D1 Database via the `@prisma/adapter-d1` driver adapter. The prerequisites are to install Prisma and integrate Wrangler to bind with your Hono project. This is an example project since all documentation for Hono, Prisma, and D1 Cloudflare is separated and doesn't have exact, precise step-by-step instructions.

### Setup Prisma

Prisma and D1 are using a binding in Wrangler to secure a connection with an adapter.
Prisma and D1 are using a binding in Wrangler to secure a connection with an adapter. This section uses Prisma ORM 7, so the commands pin the major version.

```bash
npm install prisma --save-dev
npx prisma init
npm install @prisma/client
npm install @prisma/adapter-d1
npm install prisma@7 --save-dev
npx prisma init --datasource-provider sqlite
npm install @prisma/client@7 @prisma/adapter-d1 dotenv
```

After this, Prisma will generate schema for your database; define a simple model in `prisma/schema.prisma`. Don't forget to change the adapter.
After this, Prisma will generate schema for your database; define a simple model in `prisma/schema.prisma`. Driver adapters are generally available, so no preview feature flag is needed. Use the `prisma-client` generator with the `cloudflare` runtime.

```ts [prisma/schema.prisma]
```prisma [prisma/schema.prisma]
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"] // change from default
provider = "prisma-client"
runtime = "cloudflare"
output = "../src/generated/prisma"
}

datasource db {
provider = "sqlite" // d1 is sql base database
url = env("DATABASE_URL")
}

// Create a simple model database
Expand All @@ -170,40 +205,53 @@ model User {
email String @unique
name String?
}


```

### D1 Database

If you already have D1 database ready skip this. But if not, create one resources, which can be found in [here](https://developers.cloudflare.com/d1/get-started/).

```bash
npx wrangler d1 create __DATABASE_NAME__ // change it with yours
npx wrangler d1 create __DATABASE_NAME__ # change it with yours
```

Make sure your DB is binding in `wrangler.toml`.
Make sure your DB is bound in your Wrangler config.

::: code-group

```jsonc [wrangler.jsonc]
{
"d1_databases": [
{
"binding": "DB", // i.e. available in your Worker on env.DB
"database_name": "__DATABASE_NAME__",
"database_id": "DATABASE ID",
},
],
}
```

```toml [wrangler.toml]
[[d1_databases]]
binding = "DB" # i.e. available in your Worker on env.DB
database_name = "__DATABASE_NAME__"
database_id = "DATABASE ID"

```

:::

### Prisma Migrate

This command makes to migrate Prisma and change to the D1 database, either local or remote.

```bash
npx wrangler d1 migrations create __DATABASE_NAME__ create_user_table # will generate migration folder and sql file

// for generate sql statement
# generate the SQL statement

npx prisma migrate diff \
--from-empty \
--to-schema-datamodel ./prisma/schema.prisma \
--to-schema ./prisma/schema.prisma \
--script \
--output migrations/0001_create_user_table.sql

Expand Down Expand Up @@ -234,8 +282,8 @@ For using Prisma globally make a file `lib/prismaClient.ts` with code like this.

::: code-group

```ts [lib/prisma.ts]
import { PrismaClient } from '@prisma/client'
```ts [lib/prismaClient.ts]
import { PrismaClient } from '../src/generated/prisma/client'
import { PrismaD1 } from '@prisma/adapter-d1'

const prismaClients = {
Expand Down Expand Up @@ -297,9 +345,13 @@ export default app

This will return all users in the `/` route, using Postman or Thunder Client to see the result.

## Running Hono on Prisma Compute

Hono also runs on [Prisma Compute](https://www.prisma.io/docs/compute?utm_source=hono&utm_medium=docs&utm_campaign=hono_prisma_example&utm_content=compute_docs), which hosts Node.js and Bun services next to Prisma Postgres. Because that is a long-running Node.js process rather than a Worker, the app uses `@hono/node-server` and a single shared Prisma client instead of one client per request. The [Hono guide in the Prisma docs](https://www.prisma.io/docs/guides/frameworks/hono?utm_source=hono&utm_medium=docs&utm_campaign=hono_prisma_example&utm_content=compute_hono_guide) walks through it, and the [Hono example it is based on](https://github.com/prisma/prisma-examples/tree/latest/compute/hono) is open source.

## Resources

You can use the following resources to enhance your application further:

- Add [caching](https://www.prisma.io/docs/postgres/caching?utm_source=hono&utm_medium=website&utm_campaign=workers) to your queries.
- Explore the [Prisma Postgres documentation](https://www.prisma.io/docs/postgres/getting-started?utm_source=hono&utm_medium=website&utm_campaign=workers).
- Explore the [Prisma Postgres documentation](https://www.prisma.io/docs/postgres?utm_source=hono&utm_medium=docs&utm_campaign=hono_prisma_example&utm_content=next_steps_postgres_docs).
- Follow the full [Cloudflare Workers](https://www.prisma.io/docs/guides/deployment/cloudflare-workers?utm_source=hono&utm_medium=docs&utm_campaign=hono_prisma_example&utm_content=next_steps_workers_guide) guide for Prisma ORM 8 and the [Cloudflare D1](https://www.prisma.io/docs/guides/v7/deployment/cloudflare-d1?utm_source=hono&utm_medium=docs&utm_campaign=hono_prisma_example&utm_content=next_steps_d1_guide) guide for Prisma ORM 7 in the Prisma docs.
Loading