D1 + Prisma
Build a full-stack application with Prisma ORM and Cloudflare D1 Database. This guide shows you how to set up a type-safe database layer with automated migrations and a web interface using Prisma’s schema and client generation.
-
Create your project
Start by creating a new project and installing dependencies.
Terminal window mkdir prisma-d1-appcd prisma-d1-appTerminal window bun init -ybun add alchemy @prisma/client @prisma/adapter-d1bun add -D prisma @types/node @cloudflare/workers-types typescriptTerminal window npm init -ynpm install alchemy @prisma/client @prisma/adapter-d1npm install -D prisma @types/node @cloudflare/workers-types typescriptTerminal window pnpm initpnpm add alchemy @prisma/client @prisma/adapter-d1pnpm add -D prisma @types/node @cloudflare/workers-types typescriptTerminal window yarn init -yyarn add alchemy @prisma/client @prisma/adapter-d1yarn add -D prisma @types/node @cloudflare/workers-types typescript -
Login to Cloudflare
Authenticate with your Cloudflare account.
Terminal window bun alchemy loginTerminal window npx alchemy loginTerminal window pnpm dlx alchemy loginTerminal window yarn alchemy login -
Initialize Prisma
Set up Prisma in your project:
Terminal window bun prisma initTerminal window npx prisma initTerminal window pnpm prisma initTerminal window yarn prisma init -
Configure Prisma schema
Update
prisma/schema.prisma
for Cloudflare D1:prisma/schema.prisma generator client {provider = "prisma-client"output = "../src/generated/prisma"previewFeatures = ["driverAdapters"]runtime = "cloudflare"moduleFormat = "esm"}// This datasource isn't used at runtime but Prisma requires itdatasource db {provider = "sqlite"url = "file:./dev.db"}model User {id Int @id @default(autoincrement())email String @uniquename String?createdAt DateTime @default(now())posts Post[]}model Post {id Int @id @default(autoincrement())title Stringcontent String?published Boolean @default(false)authorId Intauthor User @relation(fields: [authorId], references: [id])createdAt DateTime @default(now())} -
Create TypeScript config
Create
tsconfig.json
:{"compilerOptions": {"target": "es2021","lib": ["es2021"],"module": "es2022","moduleResolution": "bundler","strict": true,"esModuleInterop": true,"skipLibCheck": true,"forceConsistentCasingInFileNames": true,"types": ["@cloudflare/workers-types", "@types/node"]},"include": ["src/**/*", "alchemy.run.ts"],"exclude": ["node_modules"]} -
Create your infrastructure
Create
alchemy.run.ts
with D1 database and Worker:alchemy.run.ts /// <reference types="@types/node" />import alchemy from "alchemy";import { D1Database, Worker } from "alchemy/cloudflare";import { Exec } from "alchemy/os";const app = await alchemy("prisma-d1-app");// Generate Prisma client before deploymentawait Exec("prisma-generate", {command: "prisma generate",memoize: { patterns: ["prisma/schema.prisma"] },});// Create D1 database with Prisma migrationsconst database = await D1Database("app-db", {name: `${app.name}-${app.stage}-db`,adopt: true,migrationsDir: "prisma/migrations",});// Create API workerexport const worker = await Worker("api-worker", {name: `${app.name}-${app.stage}-worker`,entrypoint: "src/worker.ts",adopt: true,bindings: {D1: database,},compatibilityFlags: ["nodejs_compat"],});console.log(`API available at: ${worker.url}`);await app.finalize(); -
Create environment types
Create
types/env.d.ts
for type safety:types/env.d.ts import type { worker } from "../alchemy.run.ts";export type CloudflareEnv = typeof worker.Env;declare global {type Env = CloudflareEnv;}declare module "cloudflare:workers" {namespace Cloudflare {export interface Env extends CloudflareEnv {}}} -
Create your worker with Prisma
Create
src/worker.ts
with Prisma ORM integration:src/worker.ts import { PrismaD1 } from "@prisma/adapter-d1";import { PrismaClient } from "./generated/prisma/client.ts";export default {async fetch(request: Request, env: Env): Promise<Response> {const adapter = new PrismaD1(env.D1);const prisma = new PrismaClient({ adapter });const url = new URL(request.url);try {if (url.pathname === "/users" && request.method === "POST") {// Create a new userconst body = await request.json() as { email: string; name?: string };const user = await prisma.user.create({data: {email: body.email,name: body.name,},});return new Response(JSON.stringify(user), {headers: { "Content-Type": "application/json" },});}if (url.pathname === "/users" && request.method === "GET") {// Get all users with their postsconst users = await prisma.user.findMany({include: {posts: true,},});return new Response(JSON.stringify(users), {headers: { "Content-Type": "application/json" },});}if (url.pathname === "/posts" && request.method === "POST") {// Create a new postconst body = await request.json() as {title: string;content?: string;authorId: number};const post = await prisma.post.create({data: {title: body.title,content: body.content,authorId: body.authorId,},include: {author: true,},});return new Response(JSON.stringify(post), {headers: { "Content-Type": "application/json" },});}// Default: return API inforeturn new Response(JSON.stringify({message: "Prisma D1 API",endpoints: {"GET /users": "Get all users with posts","POST /users": "Create a user (body: { email, name? })","POST /posts": "Create a post (body: { title, content?, authorId })"}}), {headers: { "Content-Type": "application/json" },});} catch (error) {return new Response(JSON.stringify({error: error instanceof Error ? error.message : "Unknown error"}), {status: 500,headers: { "Content-Type": "application/json" },});}},} satisfies ExportedHandler<Env>; -
Generate Prisma client and migrations
Generate the Prisma client and create your first migration:
Terminal window bun prisma generatebun prisma migrate dev --name initTerminal window npx prisma generatenpx prisma migrate dev --name initTerminal window pnpm prisma generatepnpm prisma migrate dev --name initTerminal window yarn prisma generateyarn prisma migrate dev --name init -
Deploy your application
Deploy your D1 database and worker:
Terminal window bun alchemy deployTerminal window npx alchemy deployTerminal window pnpm alchemy deployTerminal window yarn alchemy deployYour API will be available at the displayed URL. Test it with:
Terminal window # Get API infocurl https://api-worker.your-account.workers.dev# Create a usercurl -X POST https://api-worker.your-account.workers.dev/users \-H "Content-Type: application/json" \-d '{"email":"john@example.com","name":"John Doe"}'# Get all userscurl https://api-worker.your-account.workers.dev/users# Create a postcurl -X POST https://api-worker.your-account.workers.dev/posts \-H "Content-Type: application/json" \-d '{"title":"My First Post","content":"Hello World!","authorId":1}' -
(Optional) Tear down
Clean up all resources when you’re done:
Terminal window bun alchemy destroyTerminal window npx alchemy destroyTerminal window pnpm alchemy destroyTerminal window yarn alchemy destroy
Next Steps
Section titled “Next Steps”- Explore Prisma’s query API for more advanced operations
- Add authentication and authorization to your API
- Set up a frontend application to consume your API
- Learn about Prisma migrations for schema management