Cloudflare Next.js Deployment Skill
Deploy Next.js applications to Cloudflare Workers using the OpenNext Cloudflare adapter for production-ready serverless Next.js hosting.
Use This Skill When
- Deploying Next.js applications (App Router or Pages Router) to Cloudflare Workers
- Need server-side rendering (SSR), static site generation (SSG), or incremental static regeneration (ISR) on Cloudflare
- Migrating existing Next.js apps from Vercel, AWS, or other platforms to Cloudflare
- Building full-stack Next.js applications with Cloudflare services (D1, R2, KV, Workers AI)
- Need React Server Components, Server Actions, or Next.js middleware on Workers
- Want global edge deployment with Cloudflare's network
Key Concepts
OpenNext Adapter Architecture
The OpenNext Cloudflare adapter (@opennextjs/cloudflare) transforms Next.js build output into Cloudflare Worker-compatible format. This is fundamentally different from standard Next.js deployments:
- Node.js Runtime Required: Uses Node.js runtime in Workers (NOT Edge runtime)
- Dual Development Workflow: Test in both Next.js dev server AND workerd runtime
- Custom Build Pipeline:
next build→ OpenNext transformation → Worker deployment - Cloudflare-Specific Configuration: Requires wrangler.jsonc and open-next.config.ts
Critical Differences from Standard Next.js
| Aspect | Standard Next.js | Cloudflare Workers |
|---|---|---|
| Runtime | Node.js or Edge | Node.js (via nodejs_compat) |
| Dev Server | next dev | next dev + opennextjs-cloudflare preview |
| Deployment | Platform-specific | opennextjs-cloudflare deploy |
| Worker Size | No limit | 3 MiB (free) / 10 MiB (paid) |
| Database Connections | Global clients OK | Must be request-scoped |
| Image Optimization | Built-in | Via Cloudflare Images |
| Caching | Next.js cache | OpenNext config + Workers cache |
Setup Patterns
New Project Setup
Use Cloudflare's create-cloudflare (C3) CLI to scaffold a new Next.js project pre-configured for Workers:
npm create cloudflare@latest -- my-next-app --framework=next
What this does:
- Runs Next.js official setup tool (
create-next-app) - Installs
@opennextjs/cloudflareadapter - Creates
wrangler.jsoncwith correct configuration - Creates
open-next.config.tsfor caching configuration - Adds deployment scripts to
package.json - Optionally deploys immediately to Cloudflare
Development workflow:
npm run dev # Next.js dev server (fast reloads)
npm run preview # Test in workerd runtime (production-like)
npm run deploy # Build and deploy to Cloudflare
Existing Project Migration
To add the OpenNext adapter to an existing Next.js application:
1. Install the adapter
npm install --save-dev @opennextjs/cloudflare
2. Create wrangler.jsonc
{
"name": "my-next-app",
"compatibility_date": "2025-05-05",
"compatibility_flags": ["nodejs_compat"]
}
Critical configuration:
compatibility_date: Minimum2025-05-05(for FinalizationRegistry support)compatibility_flags: Must includenodejs_compat(for Node.js runtime)
3. Create open-next.config.ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
export default defineCloudflareConfig({
// Caching configuration (optional)
// See: https://opennext.js.org/cloudflare/caching
});
4. Update package.json scripts
{
"scripts": {
"dev": "next dev",
"build": "next build",
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
}
}
Script purposes:
dev: Next.js development server (fast iteration)preview: Build + run in workerd runtime (test before deploy)deploy: Build + deploy to Cloudflarecf-typegen: Generate TypeScript types for Cloudflare bindings
5. Ensure Node.js runtime (not Edge)
Remove Edge runtime exports from your app:
// ❌ REMOVE THIS (Edge runtime not supported)
export const runtime = "edge";
// ✅ Use Node.js runtime (default)
// No export needed - Node.js is default
Development Workflow
Dual Testing Strategy
Always test in BOTH environments:
-
Next.js Dev Server (
npm run dev)- Fast hot reloading
- Best developer experience
- Runs in Node.js (not production runtime)
- Use for rapid iteration
-
Workerd Runtime (
npm run preview)- Runs in production-like environment
- Catches runtime-specific issues
- Slower rebuild times
- Required before deployment
When to Use Each
# Iterating on UI/logic → Use Next.js dev server
npm run dev
# Testing integrations (D1, R2, KV) → Use preview
npm run preview
# Before deploying → ALWAYS test preview
npm run preview
# Deploy to production
npm run deploy
Configuration Requirements
Wrangler Configuration
Minimum requirements in wrangler.jsonc:
{
"name": "your-app-name",
"compatibility_date": "2025-05-05", // Minimum for FinalizationRegistry
"compatibility_flags": ["nodejs_compat"] // Required for Node.js runtime
}
Environment Variables for Package Exports
If using npm packages with multiple export conditions, create .env:
WRANGLER_BUILD_CONDITIONS=""
WRANGLER_BUILD_PLATFORM="node"
This ensures Wrangler prioritizes the node export when available.
Cloudflare Bindings Integration
Add bindings in wrangler.jsonc:
{
"name": "your-app-name",
"compatibility_date": "2025-05-05",
"compatibility_flags": ["nodejs_compat"],
// D1 Database
"d1_databases": [
{
"binding": "DB",
"database_name": "production-db",
"database_id": "your-database-id"
}
],
// R2 Storage
"r2_buckets": [
{
"binding": "BUCKET",
"bucket_name": "your-bucket"
}
],
// KV Storage
"kv_namespaces": [
{
"binding": "KV",
"id": "your-kv-id"
}
],
// Workers AI
"ai": {
"binding": "AI"
}
}
Access bindings in Next.js via process.env:
// app/api/route.ts
import type { NextRequest } from 'next/server';
export async function GET(request: NextRequest) {
// Access Cloudflare bindings
const env = process.env as any;
// D1 Database query
const result = await env.DB.prepare('SELECT * FROM users').all();
// R2 Storage access
const file = await env.BUCKET.get('file.txt');
// KV Storage access
const value = await env.KV.get('key');
// Workers AI inference
const response = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
prompt: 'Hello AI'
});
return Response.json({ result });
}
Error Prevention (10+ Documented Errors)
1. Worker Size Limit Exceeded (3 MiB - Free Plan)
Error: "Your Worker exceeded the size limit of 3 MiB"
Cause: Workers Free plan limits Worker size to 3 MiB (gzip-compressed)
Solutions:
- Upgrade to Workers Paid plan (10 MiB limit)
- Analyze bundle size and remove unused dependencies
- Use dynamic imports to code-split large dependencies
Bundle analysis:
npx opennextjs-cloudflare build
cd .open-next/server-functions/default
# Analyze handler.mjs.meta.json with ESBuild Bundle Analyzer
Source: https://opennext.js.org/cloudflare/troubleshooting#worker-size-limits
2. Worker Size Limit Exceeded (10 MiB - Paid Plan)
Error: "Your Worker exceeded the size limit of 10 MiB"
Cause: Unnecessary code bundled into Worker
Debug workflow:
- Run
npx opennextjs-cloudflare build - Navigate to
.open-next/server-functions/default - Analyze
handler.mjs.meta.jsonusing ESBuild Bundle Analyzer - Identify and remove/externalize large dependencies