A production-ready boilerplate for building full-stack applications with Next.js 15 on Cloudflare Workers, featuring D1 (SQLite) database, R2 object storage, and Clerk authentication.
- Next.js 15 - Latest React framework with App Router and Server Components
- Cloudflare Workers - Deploy globally on the edge with Workers
- D1 Database - Serverless SQLite database at the edge
- R2 Storage - Object storage compatible with S3 API
- Clerk Auth - Drop-in authentication and user management
- Drizzle ORM - Type-safe database queries and migrations
- TypeScript - Full type safety across the stack
- Tailwind CSS - Utility-first CSS framework
- Todo App Example - Full CRUD implementation as reference
- Node.js 20.12+ and pnpm (E2E tests use
process.loadEnvFile) - Cloudflare account (free tier works)
- Clerk account (free tier works)
git clone https://github.com/lilpacy/cloudflare-next-boilerplate.git
cd cloudflare-next-boilerplate
pnpm install- Create a free account at clerk.com
- Create a new application
- Copy your publishable and secret keys
- Create a
.env.localfile:
cp .env.example .env.local- Update
.env.localwith your Clerk keys
# Production database
pnpm run db:create
# Preview/staging database
pnpm run db:create:previewCopy the database IDs from the output and update wrangler.jsonc:
- Replace
YOUR_D1_DATABASE_ID_HEREwith production database ID - Replace
YOUR_PREVIEW_D1_DATABASE_ID_HEREwith preview database ID
# Create all required buckets
pnpm run storage:create # Main storage
pnpm run storage:create:cache # Next.js cache
pnpm run storage:create:preview # Preview storageEdit wrangler.jsonc and replace all placeholder values:
database_id: Your D1 database IDsNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: Your Clerk publishable keyNEXT_PUBLIC_BASE_URL: Your production domain (or localhost for dev)NEXT_PUBLIC_GOOGLE_ANALYTICS_ID: (Optional) Your GA4 measurement ID
# For local development
pnpm run db:migrate:local
# For production (after first deploy)
pnpm run db:migrate:prodpnpm run devVisit http://localhost:3000 to see your app!
├── app/ # Next.js App Router
│ ├── actions/ # Server Actions
│ ├── admin/ # Admin dashboard
│ ├── todos/ # Todo app example
│ ├── components/ # React components
│ └── styles/ # Global styles
├── lib/ # Shared utilities
│ ├── db/ # Database schema and client
│ ├── r2/ # R2 storage client
│ └── schemas/ # Zod validation schemas
├── drizzle/ # Database migrations
├── public/ # Static assets
├── wrangler.jsonc # Cloudflare Workers config
└── package.json # Dependencies and scripts
pnpm run dev- Start development server with Turbopackpnpm run build- Build for productionpnpm run start- Start production server locallypnpm run lint- Run ESLintpnpm run type-check- Run TypeScript type checking
pnpm run db:create- Create production databasepnpm run db:create:preview- Create preview databasepnpm run db:migrate:local- Run migrations locallypnpm run db:migrate:prod- Run migrations on productionpnpm run db:shell:local- Open local database shellpnpm run db:shell:prod- Open remote database shell
pnpm run storage:create- Create main R2 bucketpnpm run storage:create:cache- Create cache bucketpnpm run storage:create:preview- Create preview bucket
pnpm run deploy- Build and deploy to Cloudflarepnpm run preview- Build and preview before deploying
# Against a local dev server (started automatically by Playwright)
pnpm run test:e2e
# Against the deployed preview worker
E2E_ENV=preview E2E_PREVIEW_URL=https://my-app-preview.<account>.workers.dev pnpm run test:e2eE2E tests require CLERK_SECRET_KEY in .env or .env.local (used to create
test users via the Clerk API).
Warning:
E2E_ENV=previewwipes all rows in the preview D1 database (todosandusers) before running. The preview environment is dedicated to E2E verification — do not use it for manual staging checks, and do not run preview E2E jobs concurrently.
- Ensure all Cloudflare resources are created (D1, R2)
- Update
wrangler.jsoncwith actual IDs and values - Set the Clerk secret key as a Worker secret (required for authentication in deployed environments):
pnpm dlx wrangler secret put CLERK_SECRET_KEY
pnpm dlx wrangler secret put CLERK_SECRET_KEY --env preview- Run migrations locally first:
pnpm run db:migrate:local - Deploy:
pnpm run deploy - Run remote migrations:
pnpm run db:migrate:prod
pnpm run deploySee .env.example for all available environment variables. For production, configure these in wrangler.jsonc under the vars section.
- Framework: Next.js 15 (App Router)
- Runtime: Cloudflare Workers
- Database: Cloudflare D1 (SQLite)
- Storage: Cloudflare R2 (S3-compatible)
- ORM: Drizzle ORM
- Auth: Clerk
- Styling: Tailwind CSS 4
- TypeScript: Full type safety
- Deployment: OpenNext for Cloudflare
This boilerplate includes a fully functional Todo app demonstrating:
- User authentication with Clerk
- CRUD operations with D1
- Server Actions for mutations
- Client/Server component patterns
- Type-safe database queries
- Form handling and validation
Visit /todos after signing in to see it in action.
If you want to start fresh without the Todo example:
- Delete
app/todos/directory - Delete
app/actions/todos.ts - Delete
lib/schemas/todo.ts - Update
lib/db/schema.tsto remove the todos table - Create new migration:
npx drizzle-kit generate - Update navigation in
app/components/navigation.tsx
- Define database schema in
lib/db/schema.ts - Generate migration:
npx drizzle-kit generate - Create validation schema in
lib/schemas/ - Implement Server Actions in
app/actions/ - Build UI in
app/using the example patterns
- "Table not found": Run
pnpm run db:migrate:localorpnpm run db:migrate:prod - "Database binding not found": Check
wrangler.jsoncconfiguration
- "Clerk not configured": Verify
.env.localhas correct keys - "Unauthorized": Ensure you're signed in and have proper permissions
- Build fails: Run
pnpm run type-checkto find TypeScript errors - Workers error: Verify all IDs in
wrangler.jsoncare correct - Database migrations: Ensure you ran
pnpm run db:migrate:prodafter deployment
- Next.js Documentation
- Cloudflare Workers
- Cloudflare D1
- Cloudflare R2
- Clerk Documentation
- Drizzle ORM
- OpenNext for Cloudflare
MIT
Contributions are welcome! Please feel free to submit a Pull Request.