🌏 中文版
Cloudflare Workers runs on V8 isolates, not a standard Node.js environment. Next.js depends on several Node.js APIs (fs, crypto, net, http), so deploying directly to Workers doesn’t work out of the box. @opennextjs/cloudflare is an adapter that transforms Next.js build output into a format that Cloudflare Workers can execute.
Why This Adapter Exists
Vercel’s Next.js hosting is purpose-built and offers the most complete feature support. If you want to deploy to Cloudflare instead, you have a few options:
- Static export (
next export): Only works for static sites — no SSR, no API routes - Self-hosted Node.js server: Requires managing a server, losing the serverless advantage
@opennextjs/cloudflare: Runs Next.js SSR on the Cloudflare Workers runtime
Option three is what NobodyClimb uses.
What It Does
The build process:
# First run the standard Next.js build
next build
# Then transform the output with the adapter
npx @opennextjs/cloudflare build
After the transformation, the original Next.js output is split into two parts:
.open-next/
├── worker.js # Cloudflare Worker: handles SSR and API routes
└── assets/ # Static assets: uploaded to Cloudflare Assets
The Worker handles:
- SSR for dynamic routes (parts of
page.tsxthat fetch async data) - API routes (
route.ts) - Middleware (
middleware.ts)
Cloudflare Assets handles:
_next/static/(JS chunks, CSS)- Static files from the
public/directory - Fully static pages (those using
generateStaticParamswith no dynamic data)
When a request comes in, the Cloudflare edge node first determines whether it’s for a static asset or a dynamic request. Static assets are served directly from Assets (near CDN speed); only dynamic requests go into the Worker for SSR.
Configuration
wrangler.jsonc (Cloudflare’s configuration file):
{
"name": "my-nextjs-app",
"main": ".open-next/worker.js",
"compatibility_date": "2024-11-18",
"compatibility_flags": ["nodejs_compat"],
"assets": {
"directory": ".open-next/assets",
"binding": "ASSETS"
},
"kv_namespaces": [
{
"binding": "CACHE",
"id": "your-kv-namespace-id"
}
]
}
The nodejs_compat flag enables partial Node.js API support in Workers — this is the key that makes Next.js run.
package.json scripts:
{
"scripts": {
"build": "next build && npx @opennextjs/cloudflare build",
"deploy": "npm run build && wrangler deploy",
"preview": "npm run build && wrangler dev"
}
}
Accessing Cloudflare Bindings
In the Workers environment, you can access Cloudflare bindings (D1, KV, R2) via getRequestContext():
// app/api/posts/route.ts
import { getRequestContext } from "@cloudflare/next-on-pages";
export async function GET() {
const { env } = getRequestContext();
// Query with D1
const result = await env.DB.prepare(
"SELECT * FROM posts ORDER BY created_at DESC LIMIT 10"
).all();
return Response.json(result.results);
}
This lets Next.js API routes use Cloudflare’s infrastructure directly, without setting up a separate database connection. NobodyClimb uses a standalone Hono API (also running on Workers), but the Next.js frontend accesses KV cache and other resources through the same mechanism.
Role in NobodyClimb
NobodyClimb’s web frontend is built with Next.js 15 App Router and deployed to Cloudflare Workers via @opennextjs/cloudflare. The entire system runs on Cloudflare’s infrastructure:
Browser Request
│
▼
Cloudflare Edge Node
├── Static assets → Cloudflare Assets (direct response)
└── Dynamic requests → Worker (Next.js SSR)
│
├── D1 (SQLite database)
├── KV (cache)
└── HTTP → Hono API Worker
This architecture means NobodyClimb requires zero server management — no EC2, no RDS, no load balancer configuration.
Known Limitations
This adapter isn’t a silver bullet. It has well-defined constraints:
Unsupported Next.js features:
next/imageimage optimization (requires Node.js, not supported in the Workers environment)- Some server-side
next/fontfunctionality - Full Incremental Static Regeneration (ISR) support (limited)
Workers runtime constraints:
- CPU time limit: Free plan allows up to 10ms CPU time per request; paid plans allow 30ms
- Memory limit: 128MB (Bundled); larger workloads require Unbound pricing
- No long-running tasks (requests that exceed 30 seconds will time out)
getRequestContext() only works in the Workers environment:
- For local development, use
wrangler devinstead ofnext dev— otherwisegetRequestContext()will throw an error
In practice, your package.json will likely need:
{
"scripts": {
"dev": "next dev",
"dev:worker": "npm run build && wrangler dev"
}
}
Use next dev for everyday development (fast, hot reload) and wrangler dev when testing Workers-specific behavior.
When to Use It (and When Not To)
Good fit:
- You want zero infrastructure management and can work within Cloudflare’s ecosystem constraints
- The project has moderate dynamic request volume and no long-running computations
- You’re already using other Cloudflare services (D1, R2, KV, Workers AI)
Not a good fit:
- You need
next/imageoptimization (consider Vercel or self-hosting) - Your project has complex Node.js dependencies (not all npm packages run in Workers)
- CPU-intensive SSR (Workers’ CPU time limits are strict)
- Large content sites that require full ISR support
For a community platform like NobodyClimb — moderate traffic, no complex image processing needs, everything on Cloudflare — the tradeoff makes sense. But if your Next.js app relies heavily on next/image or has pages with long SSR runtimes, this adapter will introduce additional friction.
Tradeoff Summary
| @opennextjs/cloudflare | Vercel | Self-hosted Node.js | |
|---|---|---|---|
| Infra management | None | None | Required |
| Next.js feature completeness | Partial limitations | Most complete | Full (depends on Node.js version) |
| Pricing model | Per-request | Usage/seat-based | Per server-hour |
| Cold starts | Very low (edge) | Low | None (always-on) |
| Suitable scale | Small to medium | Small to large | Medium to large |
References
- @opennextjs/cloudflare Official Docs
- OpenNext Project
- Cloudflare Workers Documentation
- Cloudflare Pages vs Workers
- Workers AI Documentation
- NobodyClimb: Building a Climbing Community Platform on Cloudflare — NobodyClimb’s full Cloudflare architecture and real-world usage of @opennextjs/cloudflare
Loading...