Server and Client Components in Next.js: When to Use Which

May 4, 2024

cutting-edgenext-jsserver-componentsclient-components

When you're playing around with modern web development, knowing the difference between server and client components is a big deal - it's all about making things run smoother and giving the users a better experience. Next.js has some clever ways of rendering components that are specially made to run on either the server or the client.

This post is going to dive into the nitty-gritty of server and client components in Next.js, and look at how we can use these ideas to build super efficient, dynamic web apps.

When it comes to web apps, here's what we've got:

Looks what happening above:

  • The Client: When you open up a website or an app on your device, your browser sends a request to the server to fetch the app's code. Then, the server sends back a response which your browser then transforms into the interface that you use to interact with the app.
  • The server is basically the computer that stores all the important stuff for your app and handles all the requests that come in from your device. It does some work to make sure you get the right response back.
Every environment has its own strengths and limitations. For instance, if you shift the rendering and data fetching to the server, you can lessen the amount of code sent to the client. This can enhance the performance of your application. However, to make your UI responsive, you need to update the DOM on the client side.

Let's dive in! First, the server side. But, one important thing to note:

The Difference Between React Server Components and Server Side Rendering (SSR)

That's totally a topic for another post, but let me at least give you the gist of it.

  • SSR: With SSR, the first page load is everything. Basically, you're sending HTML to the browser and then loading up all your typical React JavaScript. Once the JavaScript has loaded and the app is functional, it's considered hydrated. This means that your app works just like a regular React app after the initial page load. It doesn't matter if you're using SSR or not.
  • Server Components: React Server Components are components that are always rendered on the server. You'll need them when you want to fetch some data from your backend. It just makes sense to put these components in the same place as the data that's being fetched. So, whenever we need to refresh some parts of our app, we fetch those components from the server and combine them with the existing React component tree on the client-side. The coolest part is that even though we're refreshing parts of the view from the server, the client state remains preserved.
React Server Components have a higher probability of minimizing the bundle size. SSR apps are mostly about the first page load. After that, when the client starts exploring the app, they will most likely end up downloading all the dependencies since the app runs on their side. Keep in mind that if you have dependencies for a React Server Component, those dependencies will only exist on the server. This is because the React Server Components are not sent to the front-end until they have been rendered.

Great! With that introduction, let's delve into the differences between Server and Client Components in NextJs.

Server Components

With RSC, you can create UI that can be rendered and cached on the server. This means that your website can load faster, especially for users with slower internet connections. Next.js splits up the rendering work based on route segments, which lets us stream and partially render the content. There are also three server rendering strategies in Next.js:

Benefits:

  1. Data Fetching Efficiency: One great thing about Server Rendering is that it can handle data fetching on the server-side, which is super efficient because it's closer to the source of the data. This means that you get your data faster, which is awesome.
  2. Security: By using Server Components, you can keep your sensitive data and logic safe from the client-side environment. This feature creates a highly secure enclave for tokens, API keys, and other crucial information. Keeping this information safe from potential exposure can help strengthen the security of your application
  3. Caching for Optimization: Server Components facilitates result caching, enabling the reuse of rendered content across subsequent requests and users. This caching mechanism not only enhances performance but also contributes to cost reduction by curtailing the rendering and data-fetching overhead per request.
  4. Performance Optimizations: Server Components equip developers with additional tools to fine-tune performance metrics beyond the baseline. For instance, strategically migrating non-interactive UI components from Client Components to Server Components minimizes the client-side JavaScript footprint. This optimization proves invaluable for users with slower internet connections or less powerful devices, as it streamlines the download, parsing, and execution of client-side JavaScript.
  5. Swift Page Loading and FCP: Leveraging server rendering expedites the initial page load and the crucial First Contentful Paint (FCP). By generating HTML content on the server, users can access the page promptly, bypassing the wait for JavaScript download, parsing, and execution on the client-side.
  6. SEO and Social Network Enhancements: The rendered HTML output serves as a boon for search engine optimization (SEO) efforts and enhances the shareability of your content on social networks.
  7. Streamlined Rendering via Streaming: Server Components facilitate rendering optimization through chunk-based streaming to the client. This incremental rendering approach enables users to visualize page components progressively, without the need to await the completion of the entire server-side rendering process.
By default, Next.js uses Server Components which means that you can easily implement server rendering without any extra setup. If you want to use Client Components instead, you need to declare a boundary between a Server and Client Component modules. This means that by defining a "use client" in a file, we're gonna talk about that next

Client Components

Client Components enable you to craft interactive user interfaces that are pre-rendered on the server and can utilize client JavaScript to operate within the browser.

Benefits:

Rendering work on the client has a couple of benefits, like:

  1. User Interactivity Client Components can use state, effects, and event listeners to provide immediate feedback to the user and update the UI.
  2. Browser APIs: Client Components can use things like geolocation or localStorage because they have access to browser APIs.

Harnessing the Power of Client Components in Next.js

Integrating Client Components into your Next.js applications introduces a dynamic layer of interactivity and responsiveness. To seamlessly incorporate these components, you can employ the React directive "use client" strategically within your codebase.

The "use client" directive serves as a delineator between Server and Client Component modules. By inserting "use client" at the beginning of a file, preceding your imports, you establish a boundary within which all subsequent modules, including child components, become part of the client bundle.

Consider the following example illustrating the implementation of a simple counter component:

// app/counter.tsx

'use client'

import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}

Check out the picture below, it shows a visual representation of this tricky situation:

It's really important to define the client boundary using the "use client" directive, as shown in the scenario above.

By adding this instruction to toggle.js, you're telling React to switch to the client-side mode. This allows you to use some of the important client-side APIs like onClick and useState.

There seems to be some confusion regarding the rendering of the Client Components. Let's address this now:

How it works?

Client Components in Next.js are rendered differently based on whether the request is for a full page load or a subsequent navigation.

How Full Page Load Works in Next.js

When we access a Next.js app, it loads really fast. That's because Next.js uses a cool trick where it prepares a static HTML preview of the page on the server. This happens for both types of components it uses—Server and Client Components.

Here’s what goes on behind the scenes:

On the server side, React transforms Server Components into a unique format known as the React Server Component Payload (RSC Payload), which also references Client Components. Next.js then takes this payload and the JavaScript for Client Components to generate the route's HTML on the server.

Once this HTML hits the client side, it quickly displays a non-interactive preview of the route. The RSC Payload steps in to sync up the Client and Server Component trees and refresh the DOM. Finally, the JavaScript kicks in to hydrate the Client Components, bringing them to life with interactive features.

What is hydration? Hydration is the process of attaching event listeners to the DOM, to make the static HTML interactive. Behind the scenes, hydration is done with the hydrateRoot React API.

Conclusion:

Using server and client components in Next.js can help you create high-performing and efficient web apps. Server components decrease loading time and improve user experience by fetching and rendering data faster. Meanwhile, client components enhance interactivity by using browser capabilities.

© 2025 Erick Eduardo. All rights reserved.