Chinwike Maduabuchi Frontend developer passionate about software engineering.

React Server Components in Next.js 13

8 min read 2511

React Server Components in Next.js 13

Editor’s note: This article was last updated on 10 August 2023 to include updates to Server Components since the release of React 18 and Next.js 13.

There have been continuous efforts to deliver a consistent rendering solution for React apps. In May 2023, with the release of React 18, the React team announced better support for the experimental feature React Server Components (RSCs).

RSCs are now enabled by default for the App Router in React 18 and Next.js 13. They pre-render components on the server, which eliminates the work that is typically done by the client, resulting in components with zero bundle size and improved load times for your web pages. All frameworks that are compatible with the latest releases of React 18, including Next.js, Gatsby, and Remix, come with built-in support for RSC.

In this tutorial, we will explore when and how to utilize React Server Components within a Next.js application. We’ll also dive into the modifications made to the traditional React components and how to effectively combine both types of components.

Jump ahead:


It’s worth mentioning that RSC is still an experimental feature and is under development. It is recommended to use caution when implementing RSC in production.

Before we continue with the tutorial, it’s important to ensure that you have a fundamental grasp of React and Next.js, as well as a Next.js 13 starter or blank project.

You can choose to either install Next.js on your local machine or use an online platform such as StackBlitz to speed up the process. When using online tools, make sure that they provide a Next.js 13 application rather than an older version.

I am using the standard create-next-app utility with npx to create a local Next.js application. If you are using a package manager other than npm, refer to this resource for instructions on how to implement CNA with them:

npx create-next-app@latest

Here is an image to demonstrate the process, where the installer suggests using the App Router. If you choose “No,” you will get the Pages Router, which will give you the traditional Next.js 12 app experience. Make sure to use the App Router to be able to use RSCs:

Using App Router To Be Able To Use RSCs

You can choose other options based on your needs, such as using a traditional src directory, incorporating TypeScript, integrating Tailwind CSS, etc. I’m keeping things minimal for the sake of simplicity.

What are React Server Components?

Server Components are a way of executing React components on the server side and then sending the rendered output to React on the client side. This means that you don’t have to ship all of the dependencies that your project depends on, hence resulting in a faster initial page load.

RSCs are built on top of next-generation tooling and are still in the experimental phase, not yet ready for production. However, it is claimed that they have the potential to significantly improve the security, performance, and efficiency of React applications.

As discussed before, RSCs are components that are stored and guaranteed to render on the server. This way of operating gives them three main advantages:

  • Direct access to the backend: Which makes fetching data from the databases faster
  • Smaller bundle size: RSCs contribute nothing to the overall bundle size of your application. This means you can even import large libraries without worrying about the overall application’s size
  • No confidential files are sent to the client: RSCs are not rendered on the client side, ensuring that the files are never exposed to the browser. This is important when working with API keys and auth tokens, as all of this sensitive data is kept on the server side

However, RSCs lack integration with the browser, which means they do not have client-side interactivity or state management capabilities. As a result, React Hooks such as useState, useEffect, and certain other Next.js APIs are not supported by RSCs.

Understanding Server Components in Next.js 13

Next.js 13 introduces a number of changes to the way components are created and rendered, including the introduction of React Server Components.

The biggest change is that the Pages Router is now accompanies by the App Router. We can choose between using these two routers when creating our app.

The App Router is a new routing system that is built on top of RSCs and provides support for nested routes, layouts, loading states, error handling, and more:

The New Routing System Built On Top Of RSCs

This change has also affected the way we use components in Next.js. Now, there are two types of React components: Server Components and Client Components. Any component that is placed within the App Router is considered a Server Component by default. Server Components are rendered on the server and then sent to the client as static HTML. Client Components are rendered on the client, as is conventionally done with React.

With the App Router, the getStaticProps and getServerSideProps methods are no longer preferred for passing data as props. Instead, a new native fetch API has been introduced. This API works in both Server and Client Components and supports incremental static regeneration (ISR) as well.

The Suspense feature in React 18 now supports data fetching, which allows you to fetch data asynchronously and render the page as soon as the data is available. This is inherited by Next.js 13, and we will see it in action later.

Before we get into the details of RSCs, let’s take a moment to review the pre-rendering solutions that Next.js uses, the challenges they pose, and how RSCs effectively address those challenges.

Techniques for pre-rendering content in Next.js

Next.js already has some clever ways to pre-render content efficiently. Let’s walk through these techniques one by one and explore the need for React Server Components in comparison.

Server-side rendering (SSR)

In server-side rendering (SSR), the data for your app is fetched on the server and HTML pages are generated for each route. These pages are then sent to the user’s browser. When the browser receives the pages, it executes JavaScript code on the client side to add interactivity to the HTML, a process commonly referred to as hydration.

This ensures that users see content as soon as they land on your page, rather than a blank white screen while external data is being fetched, which is often the case with single-page React apps.

Static site generation (SSG)

In traditional JavaScript-based websites (SPAs mostly), the process of compiling and rendering the website is done at runtime, in the browser. Next.js improves upon this by compiling and rendering the website at build time by default.

The build output is a bunch of static files, including HTML files and assets such as JavaScript and CSS. Similar to SSR, this method pre-renders the website’s content to the user, eliminating the need for them to wait for a significant amount of JavaScript to download and execute in their browser before the website becomes visible.

The drawbacks of SSR and SSG

Despite their success, both SSR and SSG have their drawbacks. SSR websites can be expensive to host, and SSG can drastically increase build time as your application grows larger. It is recommended to go through this SSR vs. SSG guide before making a choice between the two.

Pre-rendering with React Server Components

RSCs don’t replace the existing rendering methods in Next.js, but they mix up well with both SSR and SSG to pre-render individual components on the server, which can improve performance and reduce the need for client-side JavaScript and high build times.

In the next section, we’ll take a closer look at how React Server Components can be implemented to improve the performance and flexibility of your Next.js application.

Implementing Server Components

Here’s a brief example that demonstrates the parallels between constructing a React Server Component and a conventional React component:

const ServerComponent = () => {
  const data = "I'm a Server Component.";
   * Since this is a server component, the below message  
   * won't be displayed in the browser's dev console.

  return <p>{data}</p>;

export default ServerComponent;

To use this RSC, you would import it into the page.js or page.tsx file for the route that you want to use it on. When you run the app, you will see that the HTML returned by the RSC is not injected or managed by JavaScript. Instead, it is clearly visible in server logs or the original source code, just like on a traditional server-based website:

The HTML Returned By The RSC Is Visible In Server Logs

Here is another example that illustrates the use of React Server Components for data fetching. The built-in Next.js fetch API is still an experimental feature, but it is a strong tool for getting data from a variety of sources like APIs, databases, and files. It works on both the server and client parts and has features like caching and incremental static regeneration (ISR).

Here, I am using a mock JSON API to load specific content, which can then be easily iterated over to structure and then export the component:

import { Suspense } from "react";

// Next.js fetch API in action
async function loadPosts() {
  const res = await fetch("");
  return res.json();

const PostList = async () => {
  const posts = await loadPosts();
  return (
    <div className="post-list">
      { => (
        <div key={} className="post-listing">
          <h3 className="post-title">{post.title}</h3>
          <p className="post-body">{post.body}</p>

export default PostList;

We can now use this Server Component anywhere to display a list of posts that were originally retrieved from the server through an API.

To add a loading state using Suspense, we can wrap the PostList component within a Suspense component, providing a fallback that renders a loading state while the data is being fetched. Once the data retrieval is complete, the Suspense component will render the list of posts:


const Index = async () => {
  return (
      <Suspense fallback={<h2>Loading...</h2>}>
        <PostList />


Adding An Effortless Loading State With A Suspense Fallback

If the child component that is wrapped in <Suspense> needs to do extra computation, it will be done in parallel with the asynchronous operation. This will prevent the rest of the app from being blocked while the child component is computing.

Using React Suspense for fallbacks

Coupled with Client Components and React Suspense, RSCs can pre-render content through HTTP streaming. HTTP streaming is a technique that allows a web server to send data to a client in a continuous stream, rather than in a single large file. This technique is primarily used for transferring dynamic data, such as live video or audio.

The Suspense feature supports data fetching in React 18 and allows you to show a fallback component while a component is loading. This can be useful for showing a loading spinner or a placeholder while a component is fetching data from the server.

Using Client Components with Server Components

Client Components are primarily rendered on the client side, as you might already know from your experience with React. As previously discussed, components placed within the App Router are considered Server Components. To designate a component as a Client Component, React now requires you to use the 'use client' directive, as Client Components are not rendered on the server.

Take a look at the following example to understand how Client Components are designated:

"use client"; // This statement is required to mark a component as a client component
import { useState } from "react";

const PostUpvoteButton = ({ upvotes, children }) => {
  const [upvoteCount, setUpvoteCount] = useState(upvotes);
  return (
      <button onClick={() => setUpvoteCount(upvoteCount + 1)}>
        {upvoteCount} Upvotes
export default PostUpvoteButton;

It’s not obligatory to label all Client Components with 'use client', especially if they aren’t meant to be directly employed. You can import them into a Client Component that carries the 'use client' directive, and they will function as intended.

Additionally, it’s important to note that you can’t directly import a Server Component into a Client Component. If you need to nest a Server Component within a Client Component, you can elevate it to a higher-order component and pass it as a prop to the Client Component.

Here’s an example that illustrates the proper usage of Server Components within Client Components:

const ClientComponent = ({ children }) => {

  return (
    <div className="...">

export default ClientComponent;

We can now import the ClientComponent component into a server or a route component as we normally would and provide it with another Server Component as its child, as shown in the code below:

import ClientComponent from "./ClientComponent";
import NestedServerComponent from "./NestedServerComponent";

const Index = () => {

  return (

export default Index;

All of the code provided above can be found in this GitHub repository. The repository contains separate routes for each demonstration. For example, you can locate the Suspense example under the /suspense-posts route, while the component nesting example is accessible via the /nesting route.

Advantages of React Server Components

React Server Components offer a considerable number of advantages over traditional React components, with some of the main ones listed below:

  • Enhanced performance: RSCs can significantly boost the performance of your Next.js app by reducing the browser’s workload. This improvement can lead to quicker loading times and smoother interactions
  • Improved SEO: RSCs elevate the SEO of your Next.js apps by ensuring up-to-date and fast-loading pages. This, in turn, can lead to enhanced search performance for your application on search engines
  • Increased flexibility: RSCs offer greater flexibility in how you render your Next.js applications. This flexibility allows you to create more dynamic and diverse content experiences

Disadvantages of React Server Components

Despite the numerous benefits, React Server Components do come with a few drawbacks:

  • Complexity: Implementing RSCs can be more complex than traditional React components. This may require a steeper learning curve and the adoption of more careful development practices
  • Limited compatibility: RSCs are not compatible with all libraries and tools in the React ecosystem. Some existing libraries may not integrate seamlessly with this new approach


The official release of React Server Components marks a significant shift in how we build React and Next.js applications. RSCs have the potential to revolutionize the way we build these apps by effectively managing rendering and enabling us to build apps that span both the server and client.

While it may initially feel a bit overwhelming and confusing due to the substantial changes, we can look forward to the stabilization of the RSC feature, which is bound to contribute to an improved developer experience in the future. For now, there is no harm in using the Pages Router and sticking to traditional app development methods.

Get set up with LogRocket's modern React error tracking in minutes:

  1. Visit to get an app ID.
  2. Install LogRocket via NPM or script tag. LogRocket.init() must be called client-side, not server-side.
  3. $ npm i --save logrocket 

    // Code:

    import LogRocket from 'logrocket';
    Add to your HTML:

    <script src=""></script>
    <script>window.LogRocket && window.LogRocket.init('app/id');</script>
  4. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • ngrx middleware
    • Vuex plugin
Get started now
Chinwike Maduabuchi Frontend developer passionate about software engineering.

Leave a Reply