Making Sense of React Server Components
joshwcomeau.com

Making Sense of React Server Components

articles

20 highlights

Hydration is like watering the “dry” HTML with the “water” of interactivity and event handlers.

And so, that's SSR in a nutshell. A server generates the initial HTML so that users don't have to stare at an empty white page while the JS bundles are downloaded and parsed. Client-side React then picks up where server-side React left off, adopting the DOM and sprinkling in the interactivity.

The way I see it, “Server Side Rendering” is an umbrella term that includes several different rendering strategies. They all have one thing in common: the initial render happens in a server runtime like Node.js, using the ReactDOMServer APIs. It doesn't actually matter when this happens, whether it's on-demand or at compile-time. Either way, it's Server Side Rendering.

At a high level, React Server Components is the name for a brand-new paradigm. In this new world, we can create components that run exclusively on the server. This allows us to do things like write database queries right inside our React components!

The key thing to understand is this: Server Components never re-render. They run once on the server to generate the UI. The rendered value is sent to the client and locked in place. As far as React is concerned, this output is immutable, and will never change.

This means that a big chunk of React's API is incompatible with Server Components. For example, we can't use state, because state can change, but Server Components can't re-render. And we can't use effects because effects only run after the render, on the client, and Server Components never make it to the client.

The name “Client Component” implies that these components only render on the client, but that's not actually true. Client Components render on both the client and the server.

I know that all this terminology is pretty confusing, so here's how I'd summarize it:

React Server Components is the name for this new paradigm. • In this new paradigm, the “standard” React components we know and love have been rebranded as Client Components. It's a new name for an old thing. • This new paradigm introduces a new type of component, Server Components. These new components render exclusively on the server. Their code isn't included in the JS bundle, and so they never hydrate or re-render.

**React Server Components vs. Server Side Rendering**

React Server Components is not a replacement for Server Side Rendering.

We still rely on Server Side Rendering to generate the initial HTML. React Server Components builds on top of that, allowing us to omit certain components from the client-side JavaScript bundle, ensuring they only run on the server.

As a general rule, if a component can be a Server Component, it should be a Server Component.

Server Components tend to be simpler and easier to reason about. There's also a performance benefit: because Server Components don't run on the client, their code isn't included in our JavaScript bundles. One of the benefits of the React Server Components paradigm is that it has the potential to improve the Page Interactive (TTI) metric.

Client Components can only import other Client Components.

Client Components can only import other Client Components.

This does mean that while our JS bundles get smaller, the HTML file gets larger. Instead of having the component definition in a JS file, we have the component's returned value inlined in a `

When our Server Components are rendered in the Node.js runtime, the JavaScript objects they return will be created. That can happen either on-demand or during the build.

This means that it's possible to use React Server Components without a server! We can generate a bunch of static HTML files and host them wherever we want. In fact, this is what happens by default in the Next.js App Router. Unless we really need things to happen “on-demand”, all of this work happens ahead of time, during the build.

The most obvious benefit is performance. Server Components don't get included in our JS bundles, which reduces the amount of JavaScript that needs to be downloaded, and the number of components that need to be hydrated

But here's something I find really cool: we no longer have to make the same compromises, in terms of features vs. bundle size!

A proper syntax-highlighting library, with support for all popular programming languages, would be several megabytes, far too large to stick in a JS bundle. As a result, we have to make compromises, trimming out languages and features that aren't mission-critical.

But, suppose we do the syntax highlighting in a Server Component. In that case, none of the library code would actually be included in our JS bundles. As a result, we wouldn't have to make any compromises, we could use all of the bells and whistles.

We never have to worry about dependency arrays, stale closures, memoization, or any of the other complex stuff caused by things changing.