Skip to content

SYSTEM Cited by 3 sources

OpenNext

OpenNext (opennext.js.org) is an open-source adapter layer that makes Next.js applications deployable on runtimes other than Vercel — including Cloudflare Workers, AWS Lambda, Netlify, and others. Historically Next.js has assumed Vercel-specific runtime primitives; OpenNext fills the gap so the same app can run cross-platform.

The Cloudflare-specific integration package is opennextjs-cloudflare.

Architecture role

OpenNext sits between:

  • Above: the Next.js / React render pipeline (user code + Next.js framework + React SSR).
  • Below: the host runtime's HTTP API (Workers' Request / Response, Lambda's invocation protocol, etc.).

Its translation job includes: request/response shape adaptation, streaming response mechanics, the build step that produces runtime-compatible output, Next.js caching / revalidation glue, middleware integration, and cookie/header handling.

Inefficiencies surfaced by the 2025-10-14 benchmark

Cloudflare's Workers-team profiling of cf-vs-vercel-bench flagged OpenNext (and some Next.js / React itself) as hot for avoidable allocations and copies. Named findings:

  • pipeThrough() creating 50 × 2048-byte Buffer instances per render, whether they are actually used or not.
  • opennextjs-cloudflare needlessly copying every chunk of streamed output data as it exits the renderer and enters the Workers runtime. The benchmark returned 5 MB per request, so the copy cost compounded.
  • Buffer.concat(chunks) called just to read .length. A getBody() helper would concat all chunks into a single buffer and return it; callers doing getBody().length just wanted the byte count and discarded the buffer. An obvious fix.
  • Node.js streams ⇆ Web Streams adapters that double-buffer (see concepts/stream-adapter-overhead) — e.g. Readable.toWeb(Readable.from(res.getBody())) runs through both a Node stream's buffer and a Web stream's buffer. Replaceable with ReadableStream.from(chunks).
  • Value-oriented ReadableStreams with default highWaterMark: 1 in React/Next.js — every enqueued chunk is its own read, even for byte data where coalescing into 4096-byte blocks would be correct.
  • Dynamic-mode streaming vs static-mode buffering. When OpenNext renders a page in non-force-dynamic mode, the response is fully rendered into a single buffer before any bytes go out — catastrophic for TTFB benchmarks even though the CPU cost is no worse, just less stream-hidden.

Cloudflare began opening upstream PRs against OpenNext for these (patterns/upstream-the-fix).

Known performance bottleneck

Cloudflare's composable-cache implementation inside OpenNext (used to dedupe concurrent rendering requests for the same page) has pieces with performance issues Cloudflare explicitly names as "not going to impact the numbers for this particular set of benchmarks, we're working on improving those pieces also."

Seen in

Last updated · 200 distilled / 1,178 read