Server vs. Client Components in Next.js 13 – Building Hybrid Web Applications

Server vs. Client Components in Next.js 13 – Building Hybrid Web Applications

All about server and client side components in Next.js v13.

Next.js, the React framework of choice for many developers, has been evolving rapidly. One of the most significant features introduced in its recent release was the ability to create hybrid web applications using both server and client-side components. These components add a new dimension to building web applications by allowing developers to choose where and how their components are rendered, offering greater control and flexibility. In this blog, we'll dive into server & client components in Next.js and explore how and when to use each of them.

Rendering:

Rendering in the context of web applications refers to the process of generating and displaying the user interface (UI) and content of a web page within a user's web browser. It involves taking the underlying data, whether it's static or dynamically generated, and presenting it to the user in a visually understandable and interactive manner.

To put it in simpler words, rendering is the process of generating a web page whenever a user requests it from the browser.

There are different rendering environments, strategies, and runtimes which we can choose and implement to build our web applications.

There are two rendering environments where we can render our web applications in general – the client and the server.

We'll look into how we render web pages or components in both of these environments.

Client Side Rendering:

Let's understand what client side rendering actually is, and how it works.

In a typical client-side rendering (CSR) approach, whenever a user requests a web page from the browser, the browser downloads a minimal HTML file and JavaScript bundles. The JavaScript bundles are responsible for rendering the page in the browser as well as fetching data, and updating the DOM. So the browser has to execute the JavaScript, and make additional requests to fetch data before the web page can be fully rendered and made interactive.

This can lead to a slower initial page load, as the browser has to do all those tasks by itself before it has the page ready to be displayed to the user.

Server Side Rendering:

In server side rendering, the server generates the initial HTML markup for a specific route or page, including the application's content and data, and sends it to the client or the browser as a fully rendered HTML page.

When the browser receives this HTML, it can immediately display the content without having to wait for JavaScript to execute or make additional requests. The JavaScript bundles are then loaded in the background, and the client-side JavaScript takes over the interactivity of the application.

This approach leads to better initial page load times, improved search engine optimization (SEO), and enhanced user experience, especially for users on slow or limited network connections.

Client Components:

Client components in Next.js are rendered on the client side, just like traditional React components. Next.js official documentation has this to say about them:

Client Components allows you to write interactive UI that can be rendered on the client at request time.

Client components are useful for building interactive, real time applications. They can leverage state, effects, and event listeners, which allows them to adjust the UI and give the user rapid feedback.

Server Components:

React Server components as the name might suggest are the components which are rendered on the server. From the Next.js official documentation, we get this:

React Server Components allow you to write UI that can be rendered and optionally cached on the server.

In Next.js v13, all the components or pages are server rendered by default. They have access to your server ecosystem and are close to the server, so to speak.

In order to make a component render on the client-side, we have to use the "use client" directive on top of it.

Server Side Rendering !== React Server Components:

Server Side Rendering or SSR has been present in frameworks like Next.js, Gatsby.js, Nuxt, and others for a long time. With Server Side Rendering, we fetch an empty HTML markup from the server and send it to the client, which then downloads all the necessary JavaScript bundles and executes them. React starts the Hydration process (attaching JavaScript event listeners and behaviors) to transform the initially rendered HTML markup into an interactive webpage.

What my last sentence implies is that after the initial page load, and the webpage becoming interactive, the components making it up exhibit the behavior of client components.

Server Side Rendering or SSR is only related to the initial page load.

In other words, the components don't stay on the server. All the components are still client components, despite the fact that the initial page load was pre-rendered on the server.

SSR leads to a faster First Contentful Paint (FCP) score, but the interactivity is of the same speed. This is where React Server Components come to the rescue by incrementally streaming the content of the page from the server to the browser.

From the Next.js official documentation, we can read this:

Streaming enables you to progressively render UI from the server. Work is split into chunks and streamed to the client as it becomes ready. This allows the user to see parts of the page immediately before the entire content has finished rendering.

To rephrase, just like in SSR, we fetch data from the server, however, we don't have to wait for that data to be fetched in order to display the webpage. There will be parts of the web page like the navigation bar or the side menu which we can display beforehand. Hence, the First Contentful Page or FCP is going to be a lot faster.

Moreover, in React Server Components, the server side rendering doesn't just happen for the initial page load.

All those components that don't require any user interactivity or state hooks can be rendered on the server as React Server Components, and the server can stream them to the browser to be rendered. The server will only need to send JavaScript bundles to the browser for the client components, which will then be rendered by the browser.

Difference Between React Server Components And SSR:

We can summarize the differences between React Server Components and SSR as such:

React Server ComponentsServer Side Rendering or SSR
Are continuously rendered on the serverOccurs only for the initial page load
JS bundle size is comparatively smallerJS bundle size is huge
Faster First Contentful Paint or FCPSlower First Contentful Paint or FCP
Reduced time for the page to become interactiveMore time for the page to become interactive

When to use Which?

Next.js official documentation has a good tabular description for when to use which kind of component:

What do you need to do?Server ComponentClient Component
Fetch data
Access backend resources (directly)
Keep sensitive information on the server (access tokens, API keys, etc.)
Keep large dependencies on the server / Reduce client-side JavaScript
Add interactivity and event listeners (onClick(), onChange(), etc.)
Use State and Lifecycle Effects (useState(), useReducer(), useEffect(), etc.)
Use browser-only APIs
Use custom hooks that depend on state, effects, or browser-only APIs
Use React Class Components

In general, if your component relies on data that's available on the server or needs server-side processing, Server Components are the way to go. For interactive and client-side-dependent features, such as user interfaces that update in real-time, Client Components are the better choice.

I'll recommend you to just keep using server components which are set by default, unless you've to necessarily use client components.

Should You Avoid Using Client Components?

All the components are rendered server side by default in Next.js and server side components provide many benefits including, but not limited to:

  • Reduced time for fetching data that is needed for rendering, leading to improved performance.

  • Better security by keeping sensitive data and logic on the server, such as tokens and API keys, which are not exposed to the client.

  • Caching of results and reuse on subsequent requests, which causes further speed and performance optimization.

However, there's no taboo with using client side components when needed. As I've already mentioned, we can create hybrid web applications using client and server side components together. Even within a single web page, we can use a combination of server and client side components to create a fast, optimized, and secure web application as a whole.

Using Server And Client Components Together:

As I've already said, your web application can be a combination of both server and client components, however, it is important to keep some things in mind.

We can import client components into server components, and render them, but we can't render server components inside client components. We can, however, pass data down as props from the server components to the client components.

It is recommended to pass client components down the component tree, i.e., if you have a header component in which only the search bar is interactive with the user, then it is much better to make the search bar as a separate client component instead of rendering the entire layout for the header on the client side.

Server Components should be at the root of the component tree, and the client components should be pushed outwards,i.e., towards the leaves.

We fetch data at the top through the server components, and pass it down if required to the client components. User interaction, event handlers and accessing browser APIs can be handled in the client components at the leaf level.

Conclusion:

By utilizing the React Server Components alongside Client Components, and following the best practices, some of which have been outlined in this blog, you can create web applications, which are SEO and performance optimized as well as up to date with the recent releases in the Next.js ecosystem.

I would encourage you to read more about rendering in Next.js here.

Thanks for reading!