Deploying Next.js to Cloudflare Workers with OpenNext
Complete Guide to Deploying Next.js on Cloudflare Workers
Introduction
Cloudflare Workers is a powerful edge computing platform that can run your application code across hundreds of data centers worldwide. With the release of OpenNext's Cloudflare adapter, you can now deploy complete Next.js applications to Cloudflare Workers, enjoying the ultimate performance that edge computing provides.
This article will detail how to deploy Next.js projects to Cloudflare Workers using the @opennextjs/cloudflare adapter (Note: this is a different deployment method from Cloudflare Pages).
What is @opennextjs/cloudflare?
@opennextjs/cloudflare is the Cloudflare adapter for the OpenNext project. It converts Next.js build output into a format that can run on Cloudflare Workers. This adapter uses Cloudflare's Node.js compatibility layer, allowing Next.js applications to execute in Workers' workerd runtime.
Supported Features
- ✅ Static Site Generation (SSG)
- ✅ Server-Side Rendering (SSR)
- ✅ Incremental Static Regeneration (ISR)
- ✅ API Routes
- ✅ Middleware
- ✅ Image Optimization
- ✅ Next.js 14 and 15
Prerequisites
Before you begin, ensure you have:
- Node.js 18 or higher
- npm, pnpm, or yarn
- A Cloudflare account
- An existing Next.js project (or ready to create a new one)
Option 1: Create a New Next.js Project (Recommended for Beginners)
Using create-cloudflare CLI
Cloudflare provides an official CLI tool for quick project setup:
npm create cloudflare@latest my-next-app -- --framework=next --platform=workers
This command will:
- Create a new Next.js project
- Automatically configure the
@opennextjs/cloudflareadapter - Generate necessary configuration files
- Install all dependencies
After creation, navigate to the project directory:
cd my-next-app
Option 2: Add Cloudflare Workers Support to Existing Project
Step 1: Install Dependencies
In your Next.js project root directory, run:
# Using npm
npm install @opennextjs/cloudflare@latest
npm install --save-dev wrangler@latest
# Or using pnpm
pnpm install @opennextjs/cloudflare@latest
pnpm install --save-dev wrangler@latest
# Or using yarn
yarn add @opennextjs/cloudflare@latest
yarn add --dev wrangler@latest
Step 2: Configure package.json
Add the following scripts to package.json:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"build-open": "opennextjs-cloudflare build",
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
"upload": "opennextjs-cloudflare build && opennextjs-cloudflare upload",
"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
}
}
Command explanations:
build: Standard Next.js build commandbuild-open: Build using OpenNext adapterpreview: Preview Worker locallydeploy: Deploy to Cloudflare (goes live immediately)upload: Upload new version (for gradual rollouts)
Step 3: Configure next.config.js
Modify next.config.js to support Cloudflare development environment:
import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare";
// Initialize only in development environment
if (process.env.NODE_ENV === "development") {
await initOpenNextCloudflareForDev();
}
/** @type {import('next').NextConfig} */
const nextConfig = {
// Your other configurations...
};
export default nextConfig;
Step 4: Create wrangler.jsonc Configuration File
Create a wrangler.jsonc file in your project root:
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-nextjs-app",
"main": ".open-next/worker.js",
"compatibility_date": "2024-12-30",
"compatibility_flags": [
"nodejs_compat",
"global_fetch_strictly_public"
],
"assets": {
"directory": ".open-next/assets"
}
}
Important Configuration Notes:
compatibility_date: Must be set to 2024-09-23 or newer forprocess.envto work properlynodejs_compat: Must be enabled for Node.js API compatibilitymain: Points to the built Worker entry fileassets: Static assets directory
Step 5: Create open-next.config.ts (Optional)
If you need to use R2 for caching, create open-next.config.ts:
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
export default defineCloudflareConfig({
incrementalCache: r2IncrementalCache,
});
Local Development and Testing
Development Mode
Use the standard Next.js development server:
npm run dev
Access in browser at http://localhost:3000.
Preview Worker
Test your application in the local Workers runtime:
npm run preview
This will:
- Build your application
- Start a local server in the workerd runtime
- Simulate the production environment
Important: Preview mode is closer to production and should be run before deployment.
Deploy to Cloudflare Workers
Method 1: Deploy from Local
First, login to Cloudflare:
npx wrangler login
Then deploy:
npm run deploy
On first deployment, you'll be prompted to select your Cloudflare account and create a Worker name.
Method 2: Using Workers Builds (CI/CD)
Workers Builds is Cloudflare's continuous integration service that can automatically build and deploy.
Step 1: Push Code to Git
Ensure your code is pushed to GitHub or GitLab.
Step 2: Configure in Cloudflare
- Login to Cloudflare Dashboard
- Go to "Workers & Pages"
- Click "Create application"
- Select "Workers"
- Select "Connect to Git"
- Authorize and select your repository
Step 3: Configure Build Settings
In build configuration, set:
- Framework preset: Choose "None" or "Next.js"
- Build command:
npm run build-openornpx opennextjs-cloudflare build - Build output directory:
.open-next
Step 4: Add Environment Variables
In "Settings" > "Environment variables", add:
NODE_VERSION=18
Plus any other environment variables your application needs.
Step 5: Deploy
After saving the configuration, Cloudflare will automatically trigger the first build and deployment.
Configure Caching (Using R2)
For better performance, it's recommended to configure an R2 bucket for ISR caching.
Create R2 Bucket
npx wrangler r2 bucket create next-cache
Bind in wrangler.jsonc
{
"r2_buckets": [
{
"binding": "NEXT_INC_CACHE_R2_BUCKET",
"bucket_name": "next-cache"
}
]
}
Configure open-next.config.ts
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
export default defineCloudflareConfig({
incrementalCache: r2IncrementalCache,
});
Using Cloudflare Bindings
Cloudflare Workers can access various services through bindings.
Configure KV Storage
Add in wrangler.jsonc:
{
"kv_namespaces": [
{
"binding": "MY_KV",
"id": "your-kv-namespace-id"
}
]
}
Use in Next.js
Access in API Routes
// app/api/data/route.ts
import { NextRequest } from "next/server";
export const runtime = "edge";
export async function GET(request: NextRequest) {
// Get bindings from environment
const env = process.env as any;
const value = await env.MY_KV.get("mykey");
return Response.json({ value });
}
Access in Server Components
// app/page.tsx
import { getCloudflareContext } from "@opennextjs/cloudflare";
export default async function Home() {
const { env } = await getCloudflareContext();
const data = await env.MY_KV.get("mykey");
return <div>{data}</div>;
}
Environment Variable Management
Local Development
Create a .dev.vars file (similar to .env.local):
API_KEY=dev-api-key
DATABASE_URL=http://localhost:3000
Production Environment
Set via Wrangler:
npx wrangler secret put API_KEY
Or configure in Cloudflare Dashboard under "Settings" > "Variables and Secrets".
Limitations and Considerations
1. Node.js Runtime Only
The adapter currently only supports Next.js Node.js runtime, not Edge Runtime. If your code has:
export const runtime = "edge";
You need to remove this line or change it to:
export const runtime = "nodejs";
But don't worry - even using Node.js runtime, your code still runs on global edge nodes.
2. CPU Time Limits
Cloudflare Workers has CPU time limits:
- Free plan: 10ms CPU time
- Paid plan: 30ms CPU time (configurable higher)
3. Memory Limits
Workers memory limit is 128MB - avoid memory-intensive operations.
4. Unsupported Features
- Some
next/imageoptimization features may be limited - Certain Node.js native modules may be incompatible
- File system operations are restricted
Performance Optimization Tips
1. Enable ISR
Use Incremental Static Regeneration to balance performance and content freshness:
export const revalidate = 3600; // Revalidate every hour
2. Use Edge Caching
Set cache headers in API routes:
export async function GET() {
return new Response(JSON.stringify(data), {
headers: {
"Cache-Control": "public, s-maxage=3600",
"Content-Type": "application/json",
},
});
}
3. Optimize Bundle Size
Workers have bundle size limits - analyze with:
npx wrangler deploy --dry-run --outdir=dist
4. Use Cloudflare Images
For image optimization, use Cloudflare Images service instead of Next.js built-in image optimization.
Monitoring and Debugging
View Real-time Logs
npx wrangler tail
View Deployment Logs
Check in Cloudflare Dashboard at "Workers & Pages" > your project > "Deployments".
Analyze Performance
Use Cloudflare's Analytics panel to view:
- Request volume
- Error rate
- P50/P99 latency
- CPU usage time
Gradual Rollouts
Use the upload command instead of deploy to create a new version without immediately activating it:
npm run upload
Then manually control traffic switching percentages in Cloudflare Dashboard:
- 0.05% → 0.5% → 3% → 10% → 25% → 50% → 75% → 100%
This allows safe testing of new versions with quick rollback if issues are found.
Custom Domains
In Cloudflare Dashboard:
- Go to your Worker project
- Click "Settings" > "Domains & Routes"
- Add your custom domain
- Configure DNS records (if domain is on Cloudflare)
Troubleshooting
Build Failure: wrangler.jsonc Not Found
Ensure the file is in the project root, or run:
npm run build-open
It will automatically generate the default configuration.
Empty Environment Variables
Check that compatibility_date in wrangler.jsonc is 2024-09-23 or newer.
Memory Exceeded
Optimize your code to reduce memory usage, or consider moving some logic to external APIs.
Node.js API Incompatibility
Check Cloudflare's Node.js compatibility list, use supported APIs or find alternatives.
Complete Example Project
Here's a minimal project structure:
my-nextjs-app/
├── app/
│ ├── api/
│ │ └── hello/
│ │ └── route.ts
│ ├── layout.tsx
│ └── page.tsx
├── next.config.js
├── wrangler.jsonc
├── open-next.config.ts
├── package.json
├── .dev.vars
└── .gitignore
package.json
{
"name": "my-nextjs-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"build-open": "opennextjs-cloudflare build",
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy"
},
"dependencies": {
"next": "^15.0.0",
"react": "^18.3.0",
"react-dom": "^18.3.0",
"@opennextjs/cloudflare": "latest"
},
"devDependencies": {
"wrangler": "latest",
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18"
}
}
Comparison with Other Platforms
Cloudflare Workers vs Vercel
| Feature | Cloudflare Workers | Vercel |
|---|---|---|
| Global Edge Network | ✅ 300+ data centers | ✅ Limited edge nodes |
| Cold Start Time | Extremely fast (< 10ms) | Fast |
| Pricing Model | Pay per request | Per request and bandwidth |
| Free Tier | 100,000 requests/day | 100GB bandwidth |
| Next.js Integration | Requires adapter | Native support |
| DX (Developer Experience) | Good | Excellent |
Cloudflare Workers vs Pages
| Feature | Workers | Pages |
|---|---|---|
| Deployment Method | CLI/CI | Git integration |
| Flexibility | High | Medium |
| Static Asset Handling | Requires config | Automatic |
| Function Execution | Full control | Limited |
| Gradual Rollouts | ✅ | ❌ |
Summary
Deploying Next.js projects on Cloudflare Workers through the @opennextjs/cloudflare adapter has become very mature and reliable. The main advantages of this deployment method:
Advantages
- Global Edge Deployment: Code runs in data centers closest to users
- Ultra-low Latency: Cold start time is negligible
- Cost Effective: Generous free tier with pay-as-you-go pricing
- Powerful Ecosystem: Deep integration with KV, R2, D1, and other Cloudflare services
- Gradual Rollouts: Safely test and release new versions
Suitable Scenarios
- Global applications requiring low latency
- High-traffic websites needing edge caching
- API-intensive applications
- Projects requiring Cloudflare ecosystem integration
Not Suitable For
- Long-running background tasks
- Heavy file system operations
- Dependencies on specific Node.js native modules
With this guide, you should be able to successfully deploy your Next.js project to Cloudflare Workers and fully leverage the advantages of edge computing. Happy deploying!