MervCodes

Tech Reviews From A Programmer

Edge Runtime Guide: Next.js and Cloudflare Workers

1 min read

Edge Runtime Guide: Next.js and Cloudflare Workers

Running your Next.js app at the edge means your code executes in data centers physically close to your users, cutting round-trip latency and eliminating cold starts that plague traditional serverless functions. Cloudflare Workers is one of the most mature platforms for this, and pairing it with Next.js gives you a globally distributed application without managing a single server. This guide walks through what the edge runtime actually is, how to deploy Next.js to Cloudflare Workers, and the trade-offs you need to understand before committing.

What "Edge Runtime" Actually Means

The term "edge runtime" gets thrown around loosely, so let's be precise. Next.js ships with two server runtimes: the Node.js runtime (the default) and the Edge Runtime. The Edge Runtime is a lightweight environment built on Web Standard APIs—fetch, Request, Response, URL, TextEncoder, and the Web Crypto API—rather than the full Node.js standard library.

This is a deliberate constraint. By restricting the API surface to what browsers and V8 isolates support, your code can run inside Cloudflare's isolate-based Workers instead of a full Node.js process. Isolates start in under a millisecond because they don't boot a container or a runtime; they reuse a shared V8 process and simply instantiate your code. That is why edge functions have effectively zero cold starts.

The cost is compatibility. Anything that depends on Node built-ins like fs, net, child_process, or native addons will not run. Many npm packages assume a Node environment and will break. Understanding this boundary is the single most important thing before you start.

Two Paths to Running Next.js on Cloudflare

There are two distinct ways to get Next.js onto Cloudflare Workers, and choosing the right one matters.

1. @opennextjs/cloudflare (OpenNext adapter). This is the current recommended approach. It takes a standard Next.js build and adapts it to run on Workers, including support for the Node.js runtime via Cloudflare's nodejs_compat flag. Crucially, this means you are no longer forced to mark every route with export const runtime = 'edge'. You get much broader compatibility—including many Node APIs—while still deploying to Workers.

2. @cloudflare/next-on-pages (deprecated). The older adapter targeted Cloudflare Pages and required routes to use the Edge Runtime explicitly. It is now fully deprecated—Cloudflare officially recommends migrating to the @opennextjs/cloudflare adapter, which targets Cloudflare Workers (not Pages) and supports the Node.js runtime via nodejs_compat instead of requiring Edge Runtime only. If you're starting fresh in 2026, use @opennextjs/cloudflare.

The rest of this guide assumes the OpenNext adapter, since it's the path Cloudflare and the community now recommend.

Setting Up a Project

Start with a standard Next.js app, then add the adapter:

npm create cloudflare@latest -- my-app --framework=next

This scaffolds a project wired for Cloudflare, including a wrangler.toml (or wrangler.jsonc) config and the nodejs_compat compatibility flag. If you're adding this to an existing app, install the adapter manually:

npm install --save-dev @opennextjs/cloudflare wrangler

Then create an open-next.config.ts and update your wrangler.jsonc with a recent compatibility_date and the nodejs_compat flag:

{
  "name": "my-app",
  "compatibility_date": "2026-06-01",
  "compatibility_flags": ["nodejs_compat"],
  "main": ".open-next/worker.js"
}

Add convenience scripts to package.json:

{
  "scripts": {
    "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
    "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy"
  }
}

Run npm run preview to build and test locally in a Workers-like environment before shipping. This local runtime (workerd) mirrors production far more closely than next dev, so always preview before you deploy.

Handling Runtime Constraints

Even with nodejs_compat, you should design with the edge model in mind. A few practical rules:

  • Avoid heavyweight Node-only dependencies. Libraries doing image processing with native bindings, spawning subprocesses, or relying on the file system at runtime are poor fits. Check a package's requirements before adding it.
  • Read files at build time, not request time. The Workers filesystem is not a general-purpose disk. Bundle static data into your build or move it to KV, R2, or D1.
  • Use Web Crypto, not the Node crypto module, where possible. crypto.subtle is available everywhere at the edge.
  • Keep bundles lean. Workers have a compressed bundle size limit (1 MB on the free plan, larger on paid). Tree-shake aggressively and avoid pulling in massive dependencies.

If a specific route genuinely needs the strict Edge Runtime (for example, middleware), you can still opt in per-route:

export const runtime = 'edge'

But with OpenNext you rarely need to; the adapter handles the translation.

Data, Caching, and State

At the edge you don't have a local database or persistent disk, so state lives in Cloudflare's storage primitives, which are themselves globally distributed:

  • KV — eventually-consistent key-value store, ideal for config, feature flags, and cached reads.
  • R2 — S3-compatible object storage with no egress fees, good for assets and large blobs.
  • D1 — a SQLite-based relational database for structured data.
  • Durable Objects — strongly consistent, single-instance stateful coordination for things like counters, rate limiters, and real-time collaboration.

Bind these to your Worker in wrangler.jsonc, and access them through the Cloudflare environment. OpenNext also uses these primitives to power Next.js features like Incremental Static Regeneration (ISR)—you can back the cache with KV or R2 so revalidated pages persist across the global network.

For caching HTTP responses, lean on Cloudflare's cache API and standard Cache-Control headers. Next.js's fetch caching semantics and revalidate options continue to work, and the adapter maps them onto Cloudflare's infrastructure.

Performance Tips

  • Stream responses. The Edge Runtime supports streaming, and React Server Components stream naturally. Streaming means users see content sooner even for dynamic pages.
  • Push logic to the edge, keep the origin thin. Authentication checks, redirects, and personalization in middleware run at the edge before any origin work.
  • Watch your dependencies' cold parse cost. Even without cold starts, a huge bundle takes longer to parse and instantiate. Smaller code is faster code here.
  • Use regional storage wisely. D1 has a primary region; if most writes come from one geography, place it accordingly and read from replicas.

Common Pitfalls

The most frequent failure mode is assuming an npm package will "just work." It compiles fine locally under Node, then throws at runtime because it imports fs or stream in an unsupported way. Always test in the workerd preview, not just next dev.

The second pitfall is environment variables. At the edge, secrets are injected through the Workers environment binding, not process.env in the way you might expect during build. Use Wrangler secrets (wrangler secret put) for sensitive values and reference them through the request context.

Third, watch your CPU time limits. Workers enforce a CPU time budget per request (measured in milliseconds of actual compute, generous on paid plans). Long synchronous loops or heavy crypto can hit that ceiling. Offload heavy work to queues or Durable Objects.

FAQ

Do I have to rewrite my whole Next.js app to run on Cloudflare? No. With @opennextjs/cloudflare, most standard Next.js apps deploy with minimal changes. You mainly need to remove or replace dependencies that require unsupported Node APIs at runtime.

What's the difference between Cloudflare Pages and Workers for Next.js? Pages was the older target and paired with next-on-pages. Cloudflare has consolidated its full-stack story around Workers, and the OpenNext adapter targets Workers directly. New projects should use Workers.

Can I use the Node.js runtime, or am I stuck with the Edge Runtime? Thanks to the nodejs_compat flag, the OpenNext adapter supports a large subset of Node APIs. You are no longer forced to mark every route as edge, though some strict-edge features like middleware still use the Edge Runtime.

How does ISR work on Cloudflare? The adapter backs Next.js incremental static regeneration with Cloudflare storage (KV or R2), so revalidated pages persist and are served globally without hitting your origin on every request.

Is there a cold-start penalty? Practically none. Cloudflare Workers use V8 isolates that instantiate in under a millisecond, which is the core advantage of the edge model over container-based serverless.

How do I debug production issues? Use wrangler tail to stream live logs from your deployed Worker, and always reproduce locally with opennextjs-cloudflare preview, which runs the real workerd runtime rather than a Node emulation.

Wrapping Up

Running Next.js on Cloudflare Workers gives you global low-latency delivery with near-zero cold starts, and the @opennextjs/cloudflare adapter has made the experience dramatically smoother than it was a couple of years ago. The winning strategy is simple: build with Web Standard APIs in mind, test in the real workerd runtime before every deploy, and lean on Cloudflare's storage primitives for state. Get those habits right, and the edge stops being a constraint and starts being a genuine performance advantage.

Sources

Related Articles