Performance-Fresser ■ Episode 17
React ships 136 KB to the browser. Next.js promised to fix that.
A fresh Next.js project: 247 MB of node_modules. The
App Router ships 87 KB of client runtime before your first line
of code executes.
One does admire a solution that outweighs its problem by a factor of two million.
The Server Detour
JavaScript was built for the browser. Next.js moved it to the server: Server Components, Server Actions, Middleware. The pitch is compelling. Render on the server, send HTML, skip the client cost. Elegant in theory.
In practice, the server renders your HTML. Sends it. The browser displays it. Finished? No. React downloads the runtime, parses it, attaches event handlers, and rebuilds the entire component tree in memory. They call this hydration. The server did the work. The client does it again.
Twice the cost for the privilege of using JavaScript where PHP would have returned the page and moved on.
This is not a strawman. This is the documented architecture. The page is visually complete after the server response. The user sees it. But until hydration finishes, nothing is interactive. Buttons do not click. Forms do not submit. Links sometimes work, sometimes do not. The industry coined a term for this: the uncanny valley of interactivity.
The Build
Developers report production builds exceeding 30 minutes. Dev mode: 60 seconds for the first page. 15 to 20 seconds per code change. One GitHub issue documents a 15x slowdown between versions.
The fix: Turbopack. A bundler rewritten in Rust. Announced October 2022. Stable in 2025. Three years to fix the build tool of the framework that was supposed to fix React.
They chose Rust because JavaScript was too slow to bundle JavaScript. One rather appreciates the confession embedded in that decision.
The Lock
next/image requires
Vercel's image pipeline.
ISR persists to Vercel's edge, not your filesystem. Middleware
runs on Vercel's edge network. Self-host, and you are rebuilding
what the framework quietly assumes Vercel provides.
The Build Output API has existed for three years. The framework is still not portable. Cloudflare and Netlify created OpenNext, an open-source adapter project, because the framework's maintainer would not.
An open-source project that requires a coalition of competitors to become truly open. Rather novel governance, that.
The Retreat
Northflank removed Next.js. Custom React SSR. First Contentful Paint: 2.1 seconds to 0.5. Largest Contentful Paint: 5.1 seconds to 0.8. Speed Index: 8.4 seconds to 1.7. Six times faster by removing the framework.
Documenso left for React Router and Vite. Server Actions were opaque. Builds failed without explanation. After the migration: development "practically indistinguishable from production."
The State of JavaScript survey tells the broader story: Next.js positive sentiment dropped from 80% to below 60%. Usage remains high. Satisfaction does not. One recognises that pattern from Jira.
The Layer Cake
Consider the archaeology of decisions that led here:
React added a runtime to the browser. Next.js added that runtime to the server. Then shipped it back to the browser. Then rewrote the bundler in another language because the original language was too slow to process itself. Then locked the result to one deployment platform.
Each layer solves the previous layer's problem. Not one of them asks whether the first layer was necessary.
The Receipts
You wanted a faster React. You got a deployment platform with a framework attached. The receipts are public: 30-minute builds, 87 KB runtime floors, hydration that doubles every render, and vendor lock-in disguised as developer experience.
The alternative is not complicated. It is the thing the web already does: the server renders HTML, the browser displays it, and nobody has to do anything twice.