Skip to content
← All articles

React Server Components in production: what I've learned

After eighteen months of building with React Server Components via Next.js, here's what works, what's painful, and what I'd do differently.

React Server Components in production: what I've learned

I started experimenting with React Server Components in early 2023 when the Next.js App Router was still rough around the edges. Eighteen months later, I've shipped several client projects on it, and my view has solidified: RSC is the right direction for the kind of work I do, but the developer experience still has sharp edges that catch you out.

What works well

Data fetching is genuinely better. Being able to make a database query or CMS API call directly in a component, without useEffect or getServerSideProps, makes components more self-contained and easier to reason about. A component that renders a blog post just fetches the post at the top of the function and renders it. No loading states, no client-side cache management, no waterfall of data fetching hooks. For content-driven sites, this is a significant simplification.

Bundle sizes are noticeably smaller. On one project, moving from a Pages Router setup to App Router with server components reduced the client-side JavaScript from 280KB to 95KB (gzipped). That's not a theoretical benchmark, it's a real project with real components. The LCP improvement was measurable in the field, and the client's Core Web Vitals went from amber to green.

The mental model of "server by default, client when needed" has, after the initial adjustment, made my code more intentional. You have to think about whether a component actually needs to run in the browser, and the answer is usually no. A page header, a footer, a blog post body, a product description, none of these need client-side JavaScript. Marking the components that genuinely need interactivity with 'use client' makes the boundary explicit.

What's painful

The composition rules between server and client components are confusing, especially for developers new to the pattern. You can't import a server component into a client component. You can pass server components as children of client components. You can't use hooks in server components. The rules make sense once you internalise the mental model, but the error messages when you get it wrong are often cryptic, and the debugging experience is poor.

Caching has been the single biggest source of frustration. Next.js 14 changed the caching defaults from what shipped in 13.4, and the behaviour around revalidation, dynamic rendering, and the Data Cache versus the Full Route Cache is genuinely confusing. I've had issues where content updates in Sanity didn't appear on the site because a cached response was being served, and diagnosing which cache was responsible took longer than it should have. The Next.js team has acknowledged the complexity and made improvements, but it's still an area where you need to be very deliberate.

Third-party libraries remain a pain point. Many React component libraries still assume a client-side environment. I've built wrapper components for several popular libraries, which works but adds boilerplate.

One more thing

I should probably mention something that doesn't quite fit neatly into any of these sections but comes up often enough in conversations with clients that it's worth saying.

What I'd do differently

If starting a new RSC project today, we'd establish caching conventions on day one rather than figuring them out as issues arise. We'd create a clear document mapping every data source to its revalidation strategy. We'd also build more explicit client/server boundaries in the component architecture from the start, rather than discovering them as we go.

RSC is not for every project. If you're building a highly interactive dashboard or SPA, the traditional client-side React model is still simpler. But for the content-heavy, CMS-driven sites that make up most of my work, server components are a clear improvement.

If you're considering the App Router for a new project and want to learn from my mistakes, I'm happy to share, get in touch.

Chris Ryan

Chris Ryan

Managing Director

17+ years in full-stack web development, most of it leading teams agency-side across e-commerce, CMS platforms, and bespoke applications. Specialises in infrastructure, system integration, and data privacy, with hands-on experience as a Data Protection Officer. Founded Innatus Digital in 2020 to offer the kind of honest, technically-led partnership that he felt was missing from the agency world.