Back Arrow
From the blog

Server and client components in Next.js: when, how and why?

All the text and examples in this article refer to Next.js 13.4 and newer versions, in which React Server Components have gained stable status and became the recommended approach for developing applications using Next.js.

Sergei Pestov

Lead front-end developer

Next.js offers powerful capabilities for creating high-performance web applications. An important part of its functionality, with the advent of the Next App Router, is the server and client components, which allow developers to control server-side and client-side rendering, depending on their project’s requirements. Let's look at these components in more detail.

What is a Server Component (RSC) and how is it rendered?

React Server Components are rendered exclusively on the server. Their code is not included in the JavaScript bundle file, so they are never hydrated or re-rendered on the client.

By default, all components are server-side components. This allows you to automatically implement server-side rendering without additional configuration, and you can later convert a server component into a client-side component if necessary.

RSC renders in two stages on the server:

1. React renders server-side components into a special data format called RSC Payload.

2. Next.js uses the RSC payload and JavaScript instructions for client components to render HTML on the server.

Then, on the client:

1. HTML is used to instantly show a quick, interactive preview - this is only for the initial loading of the page.

2. The RSC payload is used to reconcile the client and server component trees and update the DOM accordingly.

3. JavaScript instructions are used to hydrate client components and provide interactivity to the application.

What is the RSC payload?

The RSC payload is a compact binary representation of a rendered tree of React server components. The RSC payload is used on the client to update the browser DOM and contains:

1. The rendered result of server components.

2. Placeholders for where the rendered client components should appear, and links to their JavaScript chunk files.

3. Any props passed from the server component to the client component.

Advantages of RSC 

1. Improves application performance because heavy dependencies that could be used to render the component on the server (Markdown, code highlighter, etc.) are not sent to the client.

2. Enhances web vitals application metrics (TTI, etc.)

3. HTML streaming when using RSC allows you to break the rendering work into fragments and transfer them to the client when ready. This allows the user to see parts of the page earlier, without waiting for the entire page to be fully rendered on the server.

Disadvantages of RSC

1. The RSC payload increases HTML file size

2. Secrets intended only for the server (tokens, keys, etc.) can leak to the client. Potential security issues for next.js applications are described in detail in this article.

3. Increases the mental load when choosing the appropriate component type during application development, likely requiring time to train the team.

What is a client component and how is it rendered?

Client-side components allow you to create an interactive user interface that is pre-rendered on the server and can use client-side JavaScript to execute in the browser.

To optimize the initial page load, Next.js uses the API React to render static HTML previews on the server for both client and server components. This ensures that when a user first visits your application, they immediately see the content of the page without waiting for the JavaScript client component bundle to load, parse, and execute.

Despite their name, "client components" are initially rendered on the server,but are then executed on both the server and the client.

We can easily convert a server component into a client component by adding a “use client” directive to the beginning of the file or renaming it to “counter.client.js”:

'use client';
 
export default function Counter() {
  return <div>Counter - client component</div>;
}

When to use a server component and when to use a client component?

The choice between server and client components depends on the specific requirements of  your task. Server-side components are ideal for scenarios that require accessing data on the server during rendering or retrieving data that should not be available on the client. 

Client components, on the other hand, are effective for creating interactive elements that use React hooks and browser APIs.

To understand which type of component is suitable in a particular case, you can use the helpfultable located on the next.js documentation website.

In RSC, we cannot use React hooks, Context or browser APIs. We can only use server-side component APIs such as headers, cookies, etc.

Important: Server components can import client components.

When we use client components, we can use React hooks, Context, and APIs that are only available in the browser. However, we cannot use APIs that are only available in server components, such as headers, cookies, etc.

Important: Client components cannot import server components, but you can pass a server component as a child element or property of a client component.

With the advent of React Server Components, it has become a recommended best practice to move client components to the end nodes of your component tree whenever possible. However, sometimes you need to conditionally render server-side components using client-side interactivity.

Let's say we have a client component like this:

'use client'
 
import { useState } from 'react'
 
export default function ClientComponent({
  children,
}: {
  children: React.ReactNode
}) {
  const [show, setShow] = useState(false)
 
  return (
    <>
      <button onClick={() => setShow(!show)}>Show</button>
      {show && children}
    </>
  )
}

The ClientComponent doesn't know that its children will eventually be filled with the server component's render result. The ClientComponent's only responsibility is to decide where the child elements will ultimately be placed.

// This pattern works:
// You can pass a Server Component as a child or prop of a
// Client Component.
import ClientComponent from './client-component'
import ServerComponent from './server-component'
 
// Pages in Next.js are Server Components by default
export default function Page() {
  return (
    <ClientComponent>
      <ServerComponent />
    </ClientComponent>
  )
}

With this approach, <ClientComponent> and <ServerComponent> are separated from each other and can be rendered independently. In this case, the <ServerComponent> child component can be rendered on the server before the <ClientComponent> is rendered on the client.

All possible patterns of sharing server and client components are described in detail in the documentation.

FAQ

Why use Next.js React Server Components (RSC)?

React Server Components (RSC) provide a new way to build applications that allows developers to split code between the client and server. This becomes especially useful for large-scale projects with significant amounts of data or dynamic content.

How are RSC and Next.js related? Can I use RSC without Next.js?

RSC is tightly integrated with Next.js and provides additional features to optimize page load. While you can theoretically create RSC without using Next.js, it will be much more difficult and less efficient. Next.js provides an intuitiveRSC framework, automatic preloading, and many other features that make the development process much easier.

How does this relate to Suspense?

Server Components data retrieval APIs are integrated with Suspense. RSC uses Suspense to provide loading states and to unblock parts of a stream so that the client can show content before the entire response has completed.

What are the performance advantages of using RSC?

Server Components allow you to move most of the data retrieval to the server so that the client doesn't have to make as many requests. This also eliminates the typical useEffect network waterfalls on the client for retrieving data.

Server Components also allow you to add non-interactive functionality to your application without increasing the JS bundle size. Moving functions from the client to the server reduces the initial code size and parsing time of client JS. Also, reducing the number of client components improves client processor time. The client can skip server-generated parts of the tree during reconciliation because it knows that they could not be affected by state updates.

Do I have to use RSC?

If you already have a client React application, you can think of it as a tree of client components. If that suits you, great! Server-side components extend React to support other scenarios and are not a replacement for client-side components.

Is this a replacement for SSR?

No, they complement each other. SSR is primarily a technique for quickly rendering a non-interactive version of client components. You will still have to pay the cost of downloading, parsing, and executing these client components once the HTML is loaded.

You can combine server-side components and SSR, where server-side components are rendered first, and client-side components are rendered in HTML for a fast, non-interactive rendering during hydration. When they are combined this way, you still get a fast launch time, but you also significantly reduce the amount of JS loaded on the client.

Can I gradually migrate to RSC by rewriting the project's codebase?

Yes, with the release of the new app router and RSC, the previous approach still works, and you can gradually switch to the RSC approach. It should be noted that RSC components only work in the app router. There is a detailed guide on how to transition to the new app router.

Conclusion

It's easy to start working with us. Just fill the brief or call us.

Find out more
White Arrow
From the blog
Related articles

Your last migration to Xperience by Kentico

Dmitry Bastron

The more mature Xperience by Kentico product becomes, the more often I hear "How can we migrate there?”

Kentico

5 Key Software Architecture Principles for Starting Your Next Project

Andrey Stepanov

In this article, we will touch on where to start designing the architecture and how to make sure that you don’t have to redo it during the process.

Architecture
Development
Software development

Assessing Algorithm Complexity in C#: Memory and Time Examples

Anton Vorotyncev

Today, we will talk about assessing algorithm complexity and clearly demonstrate how this complexity affects the performance of the code.

.NET

Top 8 B2B Client Service Trends to Watch in 2024

Tatiana Golovacheva

The development market today feels like a race - each lap is quicker, and one wrong move can cost you. In this race, excellent client service can either add extra points or lead to a loss dot to high competition.

Customer Service
Client Service

8 Non-Obvious Vulnerabilities in E-Commerce Projects Built with NextJS

Dmitry Bastron

Ensuring security during development is crucial, especially as online and e-commerce services become more complex. To mitigate risks, we train developers in web security basics and regularly perform third-party penetration testing before launch.

Next.js
Development

How personalisation works in Sitecore XM Cloud

Anna Bastron

In my previous article, I shared a comprehensive troubleshooting guide for Sitecore XM Cloud tracking and personalisation. This article visualises what happens behind the scenes when you enable personalisation and tracking in your Sitecore XM Cloud applications.

Sitecore

How to properly measure code speed in .NET

Anton Vorotyncev

Imagine you have a solution to a problem or a task, and now you need to evaluate the optimality of this solution from a performance perspective.

.NET

Formalizing API Workflow in .NET Microservices

Artyom Chernenko

Let's talk about how to organize the interaction of microservices in a large, long-lived product, both synchronously and asynchronously.

.NET

Hidden Aspects of TypeScript and How to Resolve Them

Dmitry Berdnikov

We suggest using a special editor to immediately check each example while reading the article. This editor is convenient because you can switch the TypeScript version in it.

TypeScript

Troubleshooting tracking and personalisation in Sitecore XM Cloud

Anna Gevel

One of the first things I tested in Sitecore XM Cloud was embedded tracking and personalisation capabilities. It has been really interesting to see what is available out-of-the-box, how much flexibility XM Cloud offers to marketing teams and what is required from developers to set it up.

Sitecore

Mastering advanced tracking with Kentico Xperience

Dmitry Bastron

We will take you on a journey through a real-life scenario of implementing advanced tracking and analytics using Kentico Xperience 13 DXP.

Kentico
Devtools

Why is Kentico of such significance to us?

Anastasia Medvedeva

Kentico stands as one of our principal development tools, we believe it would be fitting to address why we opt to work with Kentico and why we allocate substantial time to cultivating our experts in this DXP.

Kentico

Where to start learning Sitecore - An interview with Sitecore MVP Anna Gevel

Anna Gevel

As a software development company, we at Byteminds truly believe that learning and sharing knowledge is one of the best ways of growing technical expertise.

Sitecore

Sitecore replatforming and upgrades

Anastasia Medvedeva

Our expertise spans full-scale builds and support to upgrades and replatforming.

Sitecore

How we improved page load speed for Next.js ecommerce website by 50%

Sergei Pestov

How to stop declining of the performance indicators of your ecommerce website and perform optimising page load performance.

Next.js

Sitecore integration with Azure Active Directory B2C

Dmitry Bastron

We would like to share our experience of integrating Sitecore 9.3 with the Azure AD B2C (Azure Active Directory Business to Consumer) user management system.

Sitecore
Azure

Activity logging with Xperience by Kentico

Dmitry Bastron

We'll dive into practical implementation in your Xperience by Kentico project. We'll guide you through setting up a custom activity type and show you how to log visitor activities effectively.

Kentico

Interesting features of devtools for QA

Egor Yaroslavcev

Chrome DevTools serves as a developer console, offering an array of in-browser tools for constructing and debugging websites and applications.

Devtools
QA

Kentico replatforming and upgrades

Anastasia Medvedeva

Since 2015, we've been harnessing Kentico's capabilities well beyond its core CMS functions.

Kentico

Umbraco replatforming and upgrades

Anastasia Medvedeva

Our team boasts several developers experienced in working with Umbraco, specialising in development, upgrading, and replatforming from other CMS to Umbraco.

Umbraco

Sitecore Personalize: tips & tricks for decision models and programmable nodes

Anna Gevel

We've collected various findings around decision models and programmable nodes working with Sitecore Personalize.

Sitecore

Fixed Price, Time & Materials, and Retainer: How to Choose the Right Agreement for Your Project with Us

Andrey Stepanov

We will explain how these agreements differ from one another and what projects they are suitable for.

Customer success

Enterprise projects: what does a developer need to know?

Fedor Kiselev

Let's talk about what enterprise development is, what nuance enterprise projects may have, and which skills you need to acquire to successfully work within the .NET stack.

Development

Headless CMS. Identifying Ideal Use Cases and Speeding Up Time-to-Market

Andrey Stepanov

All you need to know about Headless CMS. We also share the knowledge about benefits of Headless CMS, its pros and cons.

Headless CMS

Dynamic URL routing with Kontent.ai

We'll consider the top-to-bottom approach for modeling content relationships, as it is more user-friendly for content editors working in the Kontent.ai admin interface.

Kontent Ai
This website uses cookies. View Privacy Policy.