Insight
React Server Components: What Nobody Tells You
When I first encountered React Server Components, I understood what they were technically but kept reaching for 'use client' out of habit. The docs explain the mechanics well enough. What they don't prepare you for is the shift in how you think about your component tree.
When React Server Components were announced, I read the docs, nodded along, and thought I understood them. Components that run on the server, don't ship JavaScript to the browser, can fetch data directly. Simple enough. Then I started building with them, and I spent the first week adding 'use client' to almost everything out of habit. The problem wasn't that I didn't understand the concept. The problem was that my instincts were trained on a decade of client-side React. Every time I needed state, I reached for useState. Every time I needed to fetch something, I reached for useEffect. Both of those require the client. Both of those mean 'use client'. And so I kept opting out of Server Components before I'd really given them a chance.
The shift that helped me was changing the question I asked when creating a component. Instead of 'how does this component work?', I started asking 'where does this component belong?' Does it need interactivity? Does it need browser APIs? Does it need to respond to user events? If the answer to all of those is no — and surprisingly often it is — then it belongs on the server.
Once that click happened, a few things became obvious. First, most of a typical page is actually static structure: layouts, headings, text content, navigation, cards. None of that needs to run in the browser. Keeping it on the server means less JavaScript shipped, faster initial load, and a cleaner separation between the parts of your app that are interactive and the parts that aren't.
Second, data fetching becomes dramatically simpler. Instead of fetching in useEffect, catching loading states, handling errors client-side, you just fetch in the component directly — async/await, straightforward, no ceremony. The component renders on the server with the data already there. This isn't magic; it's just moving work to a place where it's easier to do.
Third — and this is the one nobody really talks about — Server Components make you think harder about your component boundaries. When you can't just throw useState at everything, you have to actually decide what needs to be stateful and what doesn't. That discipline is good. It produces cleaner architectures, not just faster pages. The mental model I'd suggest: think of your component tree as having two zones. The server zone is everything that can be rendered once, on the server, and sent as HTML. The client zone is the interactive islands — forms, menus, anything that needs to respond to the user. The skill is in drawing the boundary clearly, as close to the leaves of the tree as possible. The further down the boundary sits, the less JavaScript you ship, and the faster the page feels.
It took me a few weeks of actual building before this stopped feeling like extra work and started feeling like the obviously right way to structure a React application. I think that's just how it goes with a genuine mental model shift. You can't read your way into it — you have to build your way in.