The hidden RSC tax
This article was drafted with AI assistance and reviewed by our team before publishing.
If your team is building on Next.js 15 and shipping React Server Components (RSCs) without a deliberate architectural strategy, you are likely accumulating a debt you cannot see yet. This article explains why most teams hit a painful, expensive rewrite threshold around the 500-component mark — and what you can do right now to avoid it.
The First 50 Components Feel Free
React Server Components — components that run entirely on the server and send only HTML to the browser, with no JavaScript shipped to the client — became the default in Next.js 15 and hit mainstream production adoption throughout 2025 and 2026. The performance wins are real and immediate. Pages load faster, bundle sizes shrink, and the first demos look great. For a small codebase, RSCs feel like a straightforward rendering upgrade, not a structural commitment. That feeling is the trap. The first 50 components rarely expose any architectural tension. Data fetching is simpler. There are no hydration errors yet. The team moves fast. But every component added after that point is making an implicit bet on where state lives, what can be serialized (converted into a transmittable format the server can pass to the client), and which parts of your UI can ever be interactive. Those bets compound quietly for the next 200, 300, 400 components — until the system's contradictions become impossible to paper over.
Why 71% of Teams Get Caught Off Guard
According to PkgPulse's 2026 report on server components, only around 29% of developers have actually used RSCs in production, despite broadly positive industry sentiment. That gap is critical. It means the majority of founding teams and CTOs making architectural decisions right now are doing so without direct experience of what happens when a server-component-first codebase scales past a few dozen features. The core misunderstanding is this: RSCs are not a rendering optimization layered on top of your existing component model. They are a hard architectural boundary — a line in your codebase that determines what can access the database, what can hold state, and what gets sent to the browser. Cross that boundary carelessly, and you create a cascade of workarounds that each feel minor in isolation but collectively constitute a parallel, unofficial architecture living inside your official one. JSManifest's breakdown of RSC patterns and pitfalls identifies this clearly: teams frequently attempt to pass non-serializable data — things like functions, class instances, or complex objects — across the server/client boundary because their component hierarchy wasn't designed with that constraint in mind from the start. Each workaround adds coupling. Each added coupling makes the next refactor more expensive. By component 400, you are not dealing with a few awkward components. You are dealing with an architecture that was designed for a world without the boundary, now forced to live in one.
What Actually Causes the Rewrite Wall
Three specific failure patterns tend to cluster around the same scale threshold: **State ownership drift.** In a typical React codebase, state often lives wherever it's convenient — pushed up when needed, passed down as props. RSCs break this pattern. Server components cannot hold state or use hooks like `useState`. If your component tree was not explicitly designed around this constraint, you will eventually discover that too much logic lives in the wrong layer. Moving it means refactoring the surrounding component tree, which means touching components that were "done." **Serialization surprises.** The server/client boundary only allows serializable data to pass through — JSON-compatible values. As Growin's production guide notes, this is one of the most common sources of runtime errors in maturing RSC codebases: developers pass callback functions or complex objects as props from server to client components, which fails silently in development but surfaces badly under production load or after a framework upgrade. **Context API collapse.** React's Context API — the standard mechanism for sharing global state like authentication status, themes, or user preferences — does not work in server components. Teams that have built their state management on context discover this not as an error message but as a slow erosion: context-dependent components must be marked `"use client"`, which pulls their entire subtree out of the server rendering model, which gradually defeats the performance and architecture advantages that justified the RSC migration in the first place. Netguru's analysis of React trends in 2026 flags this as one of the key friction points slowing otherwise well-resourced teams down.
How to Audit Before the Wall Arrives
The rewrite threshold is not inevitable. It is the product of deferring a specific set of decisions. Here is how to address them before the bill arrives. **Draw the boundary explicitly, in writing.** Before you add the next feature, document which layers of your application are server territory and which are client territory. This is not about code — it's about a shared mental model. Every developer on the team should be able to answer, without checking, whether a new component they are writing is server or client, and why. **Audit your props for serializability now.** Run through your existing components and flag every place a function, class instance, or non-JSON value is being passed from a server component to a client component. These are your structural debt markers. A small codebase can fix these in a sprint. A 600-component codebase fixes them in a quarter, if you are lucky. **Reassign state ownership deliberately.** Map out where your application state actually lives today. Categorize each piece: Is it server state (data from a database or API)? Is it global client state (authentication, preferences)? Is it local UI state (open/closed, hovered)? Server state belongs in server components or in a data-fetching layer. Global client state belongs in a client-side store, not Context. Local UI state belongs in the nearest client component. If your current architecture does not match this map, you have found your rewrite risk. **Treat "use client" as a cost, not a convenience.** Every time a developer marks a component `"use client"`, they are making a decision that affects the entire component subtree below it. That decision should be logged, reviewed, and justified — the same way you would treat a dependency addition or a database schema change. Teams that use it casually will find themselves with a client-side codebase that happens to have a few server components at the top, rather than the reverse.
The Compounding Cost Model
The reason this matters more in 2025–2026 than it did in previous React eras is that the stakes of getting the architecture wrong are now higher. RSCs are not an experimental feature you can opt out of — they are the default rendering model in the framework most SaaS and e-commerce teams are building on. The boundary is already there. The only question is whether your team is navigating it deliberately or drifting across it one component at a time. The teams that will avoid the rewrite wall are not necessarily the ones with the most senior engineers. They are the ones that recognized RSCs as an architectural contract early — and built their component model, their state strategy, and their code review practices around that contract before the codebase became too large to course-correct cheaply.