← All articles

React Server Components in production: 18 months later, what we've learned

04 March 20253 min read

After a year and a half of Server Components in real projects, we have ten pages of lessons. The four that changed how we think about web apps.

Next.js App Router has been stable since May 2023, and for the first time React Server Components landed in the hands of "normal" developers. Eighteen months later, after running them in ten projects across sizes and sectors, our views are sharp. Sharing them for anyone evaluating adoption now.

Lesson 1: the real win is colocated fetching

On paper Server Components sell performance, smaller bundles, streaming. All true, but the real developer win is elsewhere: data lives where it is used. A dashboard page no longer has a useEffect calling an API calling a controller calling a service. It has a component that simply writes await prisma.lead.findMany(...).

The learning curve is gentle, especially for those coming from PHP or Rails. For those from pure React it is a habit shift: realising you cannot use useState in a component is — literally — the first mental break.

Lesson 2: client/server is a design decision

"Use client" is not a technical annotation, it is an architectural choice. Getting it wrong yields bloated bundles (heavy components becoming client for no reason) or broken experiences (components that should be interactive and aren't).

Our rule: push "use client" as far down the tree as possible. A page is server. The form is server. The "submit" button that opens a confirm modal is client — and only that.

Lesson 3: caching is a mental model to learn

Next 13/14 caching was confusing. Next 15 is better — default is "do not cache" — but the surface stays complex. The four cache layers (request memoization, data cache, route cache, full route cache) overlap in non-obvious ways.

Our discipline: every endpoint declares its cache policy explicitly. cache: "no-store" for personal data, revalidate: 60 for non-critical dashboards, force-cache with tags and revalidateTag for public pages refreshable from a CMS.

Lesson 4: Server Components do not fix client problems

If your UI needs complex interactions — drag and drop, visual editing, real-time chat, maps — Server Components do not help directly. They help deliver initial state and skip useless JavaScript, but otherwise you are in classic React territory.

The pattern we use is "server shell, client islands": the page shell is server, interactive zones are small focused client components, shared state lives in URL searchParams or in lightweight stores (Zustand) confined to the client subtree.

What we would not redo

Server Actions for high-concurrency public forms: better to use API routes with explicit rate limiting. Server Actions are handy but make limits and auth less transparent — on public surfaces we hit surprises.

What we would redo immediately

Admin dashboards as first-class Server Components citizens. There the code reduction and mental cleanliness pay back the learning investment from day one. For landing pages or blogs, "server-by-default" is almost a non-thought: everything is server, and the site is fast.