For most of React's life, "component" meant one thing: a function that runs in the browser, re-renders on state changes, and ships its JavaScript to every visitor whether they need it or not. Server Components break that assumption, and after six months of running them in production across three client projects, we can say the performance wins are real — but they're not the part that actually changes how you build software.
The benchmark story is true, but incomplete
Yes, our largest dashboard shipped 41% less JavaScript to the client after we moved data-fetching and formatting logic into Server Components. Yes, Time to Interactive dropped by nearly a second on mid-range Android devices. Those numbers are worth chasing on their own. But they're also the easy part — swapping a fetch-on-mount `useEffect` for a server-side `async` component is mechanical work once you understand the rules.
The hard part is the mental model
What actually slowed our team down wasn't the API — it was unlearning habits. Every component used to be able to hold state, attach an event handler, or reach for a browser API. Now you have to constantly ask: does this piece of UI need interactivity, or does it just need data? That question sounds simple until you're refactoring a form with twelve nested fields, three of which need client state and nine of which are static labels pulled from a database.
Our rule of thumb ended up being: push the client boundary as far down the tree as possible. A component isn't a client component because its parent is — it's a client component because it, specifically, needs `useState`, `useEffect`, or a browser event. Everything else stays on the server by default.
Key takeaway
Server Components aren't a performance toggle you flip once. They're a boundary you redraw constantly as the app evolves — and the teams that succeed with RSC are the ones that treat "server vs. client" as a design decision, not an implementation detail.
Where it gets genuinely tricky
- Context providers. Anything using React Context has to live in a client boundary, which means a single theme provider at the root of your app can accidentally pull far more of the tree into the client bundle than you'd expect.
- Third-party libraries. Plenty of popular npm packages assume they're running in the browser. Expect to audit your dependency tree the first time you migrate a real project.
- Waterfalls, just moved. Server Components don't eliminate request waterfalls — they just move them to the server, where they're easier to fix with parallel data fetching, but easy to forget about because the network tab looks so clean.
Our verdict
Server Components are worth adopting in 2025, but budget real time for the mental shift, not just the migration. Start with a single route that's mostly static content, get your team comfortable with the server/client boundary there, and expand from a place of confidence rather than trying to convert an entire app in one sprint.