React Server Components confuse experienced React developers more than beginners, because the existing mental model actively gets in the way. This is not server-side rendering with better ergonomics. It is a different execution model where some components never reach the browser at all, and understanding that distinction is what separates teams getting real gains from teams adding complexity for nothing.
01The distinction that matters
Server-side rendering runs your components on the server to produce HTML, then ships the same component code to the browser to hydrate and make it interactive. The code runs twice and the browser downloads all of it.
Server Components run on the server and their code never ships. The output is a serialised description of the rendered result, not the component itself. A component using a large date formatting library adds nothing to the client bundle, because the library stayed on the server. That is the actual benefit, and it is a bundle-size benefit before it is a performance benefit.
02The boundary is one-directional
Server Components can render Client Components. Client Components cannot import Server Components. This asymmetry is the rule people fight hardest, and fighting it is how the benefit gets erased.
You can, however, pass a Server Component to a Client Component as a child or prop. The server renders it and passes the result through, so an interactive client-side layout can still contain server-rendered content. This composition pattern resolves most situations where the constraint initially feels impossible.
- Server Components may render Client Components directly.
- Client Components may receive Server Components as children or props.
- Props crossing the boundary must be serialisable - no functions, no class instances.
- 'use client' marks an entry point, not a single file.
03The mistake that erases the benefit
Adding 'use client' to the top of a component does not mark just that file. It marks an entry point into client-land, and everything that component imports becomes client code too. Placing it high in the tree - a layout, a provider, a shared wrapper - converts your entire application to Client Components while appearing to use the new architecture.
The fix is pushing the directive as far down as possible. A page does not need to be a Client Component because it contains a button. Make the button a Client Component and leave the page on the server. In practice this means small islands of interactivity within server-rendered structure.
04Data fetching becomes local again
The most immediately pleasant consequence is that components fetch their own data directly, with async/await, without a client-side data layer. No loading state machine, no cache invalidation library, no prop drilling from a page-level fetch.
This resurrects the waterfall problem in a new form, though. Sequential awaits in nested components serialise round trips. Fetch in parallel where the requests are independent, and use Suspense boundaries deliberately so slow sections stream in without blocking the rest of the page.
| Concern | Server Component | Client Component |
|---|---|---|
| Data fetching | Yes - direct, no client cache | Only for post-interaction data |
| Secrets and API keys | Safe - never shipped | Never - all client code is public |
| useState / useEffect | Not available | Yes |
| Event handlers | Not available | Yes |
| Heavy dependencies | Free - stays on server | Costs bundle size |
| Browser APIs | Not available | Yes |
05When it is not worth it
Highly interactive applications - editors, dashboards with live state, design tools, anything resembling a desktop app in the browser - are mostly Client Components by nature. The RSC boundary adds ceremony without much benefit when nearly everything needs interactivity.
The pattern pays off most for content-heavy applications with islands of interaction: marketing sites, documentation, e-commerce, publishing, dashboards that mostly display. If your bundle is dominated by libraries used to render content rather than to handle interaction, RSC will meaningfully shrink it. If your bundle is dominated by genuine interactivity, it will not.
Topics
Priya Iyer
Staff Engineer · SyncTrix
Writes about the engineering decisions behind production systems - architecture, delivery and the trade-offs that only show up at scale.
Building something like this?
SyncTrix engineers AI, SaaS, platform and cloud systems for enterprises and high-growth teams. Tell us what you're shipping and we'll scope it with you.