React Server Components Example with Next.js
Tags: react, nextjs, typescript, webdev
Published: 2024-04-16 19:17:12

React Server Components (oftentimes shortened to <strong>RSC</strong>) provide us with a fascinating new approach to building React applications.

That said, my experience while researching this article was <strong>far less rosy</strong> and <strong>far more expletive laden </strong>than I expected.

But now that I have been one acquainted with the RSC, I’d like to share my findings with you so that hopefully your learning journey won’t be quite as painful or confusing.

In this article, we’ll discuss a range of topics, including:
<ul>
 	<li>What are React Server Components?</li>
 	<li>Can you use React Server Components without Next.js?</li>
 	<li>How do React Server Components work in Next.js?</li>
 	<li>What are the advantages and disadvantages of React Server Components?</li>
 	<li>Are React Server Components production ready?</li>
</ul>
We’ll also go through a React Server Components example using the Next.js app router. That example will discuss RSC <strong>streaming behavior</strong> and <strong>client and server component nesting</strong>. If you’re only interested in the code example, just scroll to the bottom of the article.

Let’s begin!

## What are React Server Components?

My favorite definition of RSC comes from <a href="https://github.com/markdalgleish">Mark Dalgleish</a> in his 2023 React Advanced conference talk, “<a href="https://youtu.be/36uY-c0E_EQ?si=SipZ6fLWkd0B2pCc">Simplifying Server Components</a>”. The way he puts it is that “server components are just virtual DOM over the network”.


![Mark Dalgleish provides RSC definition](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/76iasv9he2begq06pppc.jpg)

What does this mean?

Let’s say we have a React component called `Basic`:

```typescript
const Basic = () => {
  return (
    <main>
      <p>Hello, World</p>
    </main>
  );
};
```

On the server, that component would be serialized into what’s known as an <strong>RSC payload</strong>. That would look <em>something </em>like this in the Next.js server component implementation.

```json
// ...complicated Next.js stuff up here
{
  children: [
    "__PAGE__",
    {},
    [
      "$L1",
      [
        "$",
        "main",
        null,
        {
          children: ["$", "p", null, { children: "Hello, World" }],
        },
      ],
      null,
    ],
  ];
}
// ...more complicated Next.js stuff down here
```

That RSC payload would then be streamed down to the client and rendered exactly like any other JSX.

ℹ️ <em>Sidenote: This explanation gets at the core of React Server Components, but is a little simplified. If you want to learn more about what’s happening under the hood, I highly recommend watching to <a href="https://github.com/dai-shi">Daishi Kato</a>’s “<a href="https://youtu.be/_SLh2g5N3mk?si=fSg8799Qm79nsbm3">Exploring React Server Component Fundamentals</a>” talk at React Day Berlin 2023.</em>

Seems pretty simple, right? <strong>So why bother with this RSC payload nonsense?</strong> Why not just render the component to HTML and stream <em>that</em> down to the client?

Well, we can! Typically, we would call this <strong>server side rendering</strong> (SSR).

## React Server Components vs SSR

We’ve actually been able to serialize React components to HTML for several years now.

You can find a solid <a href="https://vitejs.dev/guide/ssr">definition of SSR in the Vite documentation</a>:

> SSR specifically refers to front-end frameworks (for example React, Preact, Vue, and Svelte) that support running the same application in Node.js, pre-rendering it to HTML, and finally hydrating it on the client.

Put simply, <strong>SSR pre-renders a React component to HTML</strong>, while <strong>RSC serializes a React component into an RSC payload</strong>.

Server components have a couple advantages over traditional SSR. For one, SSR requires a hydration step once the HTML has been sent to the client; the initially loaded page isn’t interactive until the entire JS bundle is downloaded and the entire page is hydrated.

By comparison, server components require no hydration step, allowing pages to <strong>load faster</strong> <strong>and become interactive more quickly</strong>.

The page loading issues raised by SSR can be mitigated by chunking your JavaScript bundle and streaming it to the client, but eventually the entire bundle needs to be downloaded. And that bundle tends to get larger as your application grows.

Server components, meanwhile, add no additional JavaScript to your bundle. As your application grows, your JavaScript bundle size does not grow with it (assuming you <em>only</em> use server components).

ℹ️ <em>Sidenote: It’s important to note that RSC and SSR aren’t mutually exclusive. You can learn a bit more about this by reading “<a href="https://www.joshwcomeau.com/react/server-components/">Making Sense of React Server Components</a>” by Josh Comeau.</em>

## Server Components vs. Client Components
The `Basic` component above was a simple example. What happens when we add interactivity to our component?

Let’s say we add a `Counter` to our `Basic` component:

```typescript
const Basic = () => {
  return (
    <main>
      <Counter />
      <p>Hello, World</p>
    </main>
  );
};
```

When we interact with the `Counter`, we would expect the value to increment. In other words, <strong>that component has state</strong> and must be declared as a client component in our React code.

How do we represent such a component in a format that can be generated on the server and sent to the client? The answer, as you may have guessed, lies in the <strong>RSC payload</strong>.

When a bundler supporting React Server Components detects a client component, it adds a reference to that component in the RSC payload – `react.client.reference`.

![Mark Dalgleish explains RSC client references](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yiu8w02aedgtmkppu457.jpg)

The bundler also generates a manifest that maps the reference ID to the actual client component, which determines what JavaScript must be sent to the client (meaning that, unlike server components, <strong>client components</strong> <strong>will contribute to your bundle size</strong>).

In <a href="https://changelog.com/jsparty/311">Episode #311 of the Changelog podcast</a>, <a href="https://github.com/gaearon">Dan Abramov</a> said (and I’m paraphrasing a bit here) the RSC payload resulting from such scenarios can be thought of as having a `script` tag in place of the client component.

ℹ️ <em>Sidenote:</em> <em>If you’re interested in learning a bit more about how client components are serialized, take a look at “<a href="https://timtech.blog/posts/react-server-components-rsc-no-framework/">React Server Components, without a framework?</a>” by <a href="https://github.com/ziir">Tim Pillard</a>.</em>

As the late Billy Mays would say, “But wait, there’s more!”

What happens when you nest a server component <em>inside</em> that client component? As wacky as it sounds, <strong>your bundler recognizes that as a server component</strong> and serializes it as such in the RSC payload.

Don’t worry, we’ll get more into server components vs client components in our code example. But first, let’s address the elephant in the room….

## React Server Components Without Next.js…?
Daishi Kato, creator of <a href="https://github.com/pmndrs/zustand">Zustand</a> and <a href="https://github.com/pmndrs/jotai">Jotai</a>, says there are a few things we need to support RSC serialization:
<ul>
 	<li><strong>Bundler</strong> capable of recognizing client components, generating a manifest, and resolving client references on the client</li>
 	<li><strong>Server</strong> capable of accepting HTTP requests and responding with (dynamic) RSC payloads</li>
 	<li><strong>Router</strong> capable of intelligently serving resources (e.g., don’t render client components that are not useful for a given route)</li>
 	<li><strong>SSR</strong> that works in tandem with React Server Components, largely for initial page load performance</li>
</ul>
So while the RSC concept is fairly straightforward in theory, there are a number of moving parts necessary for implementing RSCs in practice.

Currently, <strong>Next.js is the only production framework that fully supports RSCs</strong>.

This isn’t an accident; when <a href="https://react.dev/blog/2020/12/21/data-fetching-with-react-server-components">Meta introduced React Server Components</a>, Dan Abramov explicitly stated that they collaborated with the Next.js team to develop the <a href="https://github.com/facebook/react/tree/main/packages/react-server-dom-webpack">RSC webpack plugin</a>.

That means you’re <em>mostly</em> limited to Next.js if you’d like to build an app with RSCs.

📣 **Important**: This article was originally written in March 2024. At the very end of that month, <a href="https://redwoodjs.com/blog/rsc-now-in-redwoodjs">RedwoodJS announced full support for server components</a>! While there still appear to be some implementation issues, RedwoodJS <em>does</em> now offer a viable alternative for implementing React Server Components in production.

### But What If I Really Don’t Like Next.js?
If you’re really against using Next.js, your options are limited and largely experimental.

The moderators at <a href="https://www.reactiflux.com/">Reactiflux</a> pointed me toward <a href="https://waku.gg/">Waku</a> (also developed by Daishi Kato) as a potential alternative. However, Daishi explicitly recommends using the framework on non-production projects.

At Node Conference 2023, Jarred Sumner (creator of <a href="https://bun.sh/">Bun</a>) showed a <a href="https://portal.gitnation.org/contents/server-components-with-bun">demo of server components in Bun</a>, so there is at least partial support in that ecosystem. The Bun repo provides <a href="https://github.com/oven-sh/bun/blob/7f16164b25a4bebb25532285ee3f25746857c5cf/packages/bun-plugin-server-components/README.md">bun-plugin-server-components</a> as the official plugin for server components. And while I haven’t looked at it in-depth, <a href="https://github.com/hex2f/marz">Marz</a> claims to be a “React Server Components Framework for Bun”.

![Jarred Sumner explains server components with Bun](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mzxbt62culxpktr5qmea.jpg)

In the Changelog Podcast episode referenced above, Dan Abramov alluded to <a href="https://parceljs.org/">Parcel</a> working on RSC support as well. I couldn’t find much to back up that claim aside from a <a href="https://github.com/parcel-bundler/parcel/issues/9050">GitHub issue discussing directives</a> and a <a href="https://twitter.com/devongovett/status/1749629092914172388">social media post by Devon Govett</a> (creator of Parcel), so I can’t say for sure if Parcel is currently a viable option for developing with RSCs.

And you can’t use React Server Components with Vite <em>right now</em>, but <a href="https://github.com/facebook/react/pull/26926">support is being worked on</a>.

## React Server Components Example with Next.js
Alright, with that out of the way, let’s get to the code example. Note that we’re using Tailwind for styling just to make the example a bit less ugly; Tailwind has no other bearing on the example.

For reference, here are our dependencies:

```json
"dependencies": {
    "react": "^18",
    "react-dom": "^18",
    "next": "14.1.3"
  },
  "devDependencies": {
    "typescript": "^5",
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "autoprefixer": "^10.0.1",
    "postcss": "^8",
    "tailwindcss": "^3.3.0",
    "eslint": "^8",
    "eslint-config-next": "14.1.3"
  }
```

We’re going to cover a few concepts here, but we’ll start with a React Server Components `Suspense` example to demonstrate how payload streaming is handled.

### React Server Components and `Suspense`
React `Suspense` can intelligently display parts of the RSC payload as they are streamed down to the client. If the component is not yet available, `Suspense` will fall back to a loading state.

Let’s say we have a component `Multiple`, which has multiple server components that take varying amounts of time to load:

```typescript
// src/app/multiple/page.tsx

const Multiple = () => {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <div className="flex w-1/2">
        <div className="flex flex-col gap-8">
          <h1 className="text-4xl">Multiple long loading things</h1>

          <Suspense fallback={<p>Loading...</p>}>
            <LongLoadingComponent />
          </Suspense>

          <Suspense fallback={<p>Loading...</p>}>
            <LongerLoadingComponent />
          </Suspense>

          <Suspense fallback={<p>Loading...</p>}>
            <LongestLoadingComponent />
          </Suspense>
        </div>
      </div>
    </main>
  );
};

export default Multiple;
```

Each server component is wrapped within a `Suspense` component, which falls back to “Loading…” text until the server component is available.

For the purposes of this example, we’ll mock each long running query with a `Promise` that resolves after a defined timeout. So each of the server components will look something like this:

```typescript
const longLoadingFetch = async () => {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Vegeta, what does the scouter say about his power level?");
    }, 2000);
  });

  return promise;
};

const LongLoadingComponent = async () => {
  const res = await longLoadingFetch();

  return (
    <div className="text-white border border-white p-4">{res as string}</div>
  );
};

export default LongLoadingComponent;
```

Each component will have a different timeout value and string to simulate different server components with different query durations.

Initially, each server component is unavailable and all display the “Loading…” text. Then the quickest component renders, then the second quickest, then the third quickest.


![React Suspense example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5nykmk73sndvs3ti8xw.gif)

In <a href="https://syntax.fm/show/718/react-server-components">Episode #718 of the Syntax podcast</a>, <a href="https://github.com/wesbos">Wes Bos</a> pointed out a handy <a href="https://chromewebstore.google.com/detail/rsc-devtools/jcejahepddjnppkhomnidalpnnnemomn">RSC Devtools Chrome extension</a> that we can use to better understand what’s going on here.


![RSC Devtools tree](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jhrpsenhl2etdxd19j72.png)

We can see that we have three lazily loaded components, which lines up with what we would expect. If we click on the first node, we see the RSC payload and the rendered content.

![RSC Devtools component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a7jl4fz9ipcvz34fs0dw.jpg)

Also note that the page header has already been rendered! The remainder of the RSC payload is streamed down to the client as it becomes available. Importantly, this means <strong>the long-running queries are not blocking page rendering</strong>.

ℹ️ <em>Sidenote: If you’d like to learn more about how the RSC payload is streamed to the client, check out “<a href="https://www.builder.io/blog/why-react-server-components#react-server-components-rendering-lifecycle">Why React Server Components Are Breaking Builds to Win Tomorrow</a>”.</em>

But you may have noticed that this example only deals with server components. Let’s examine a more complex example that involves both client and server components.

### Interleaving Client and Server Components
This is where the fun begins. In this example, we’ll be looking at how to implement some basic search functionality. Let’s take a look at the <code>Search</code> component:

```typescript
// src/app/search/page.tsx

const Search = ({
  searchParams,
}: {
  searchParams?: { [key: string]: string | string[] | undefined };
}) => {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <div className="flex w-1/2">
        <div className="flex flex-col gap-8">
          <h1 className="text-4xl">Search example</h1>

          {/* client component */}
          <CounterProvider>

            {/* client component */}
            <SearcheableToDoList>

              {/* client component */}
              <SearchField />

              <Suspense fallback={<p>Loading...</p>}>

                {/* server component */}
                <ToDoList searchParams={searchParams}>

                  {/* client component */}
                  <CounterDisplay />
                </ToDoList>
              </Suspense>
            </SearcheableToDoList>
          </CounterProvider>
        </div>
      </div>
    </main>
  );
};

export default Search;
```

I’ve added comments to indicate where there are server and client components. Note that the <code>searchParams</code> value passed into the <code>Search</code> component is a <a href="https://nextjs.org/docs/app/api-reference/file-conventions/page#searchparams-optional">Next-specific property</a> containing the query parameters for the page.

Let’s briefly discuss what the individual components are doing:
<ul>
 	<li><code>CounterProvider</code> is a <strong>client component </strong>providing a context to its children components; the context value is just <code>counterVal</code> and <code>setCounterVal</code>.</li>
 	<li><code>SearcheableToDoList</code> is a <strong>client component </strong>wrapper that uses the above context to increment the counter value on clicking a button; it displays the <code>counterVal</code>, a button to increment the counter, <em>and its children.</em></li>
 	<li><code>SearchField</code> is a <strong>client component</strong> input that updates the URL query parameters</li>
 	<li><code>ToDoList</code> is a <strong>server component</strong> that reads data from a <code>data.json</code> file, then filters that data based on the <code>searchParams</code> retrieved in the <code>Search</code> parent; it displays the resulting data <em>and its children.</em></li>
 	<li><code>CounterDisplay</code> is a <strong>client component</strong> that displays the counter value from the <code>CounterProviderContext.</code></li>
</ul>
The Next.js documentation refers to this nested pattern as <a href="https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#interleaving-server-and-client-components">“interleaving” server and client components</a>.

But how is it that we can nest a server component within our client components?

Recall that React Server Components are just <em>serialized vDOM sent over the network</em>. So as long as the content in the React tree is serializable, it can be handled without issue by your bundler.

In this case, the <code>ToDoList</code> server component is serializable specifically because it is a child of its client component wrapper. Children of a React component are really just props – and <strong>props are serializable</strong>!

[Here’s what the rendered components look like](https://www.thegnar.com/wp-content/uploads/2024/04/interleaved-components-example.gif).

<p>There are a couple other little tidbits we can glean from the interleaved components.</p>

#### You Can Still Use Contexts (Carefully)
<p>In Next.js v13+, all components are server components by default and <strong>cannot </strong>use state hooks like <code>useState</code>, <code>useEffect</code>, or <code>useContext</code>.</p>
<p>Client components operate exactly the same as before and <strong>can</strong> use state hooks. For example:</p>

```typescript
"use client";

type CounterProviderValue = {
  counterVal: number;
  setCounterVal: Dispatch<SetStateAction<number>>;
};

export const CounterProviderContext: React.Context<CounterProviderValue> =
  createContext<CounterProviderValue>({
    counterVal: 0,
    setCounterVal: () => {},
  });

export const CounterProvider: React.FC<PropsWithChildren> = ({ children }) => {
  const [counterVal, setCounterVal] = useState(0);

  return (
    <CounterProviderContext.Provider value={{ counterVal, setCounterVal }}>
      {children}
    </CounterProviderContext.Provider>
  );
};
```

<p>We declare <code>CounterProvider</code> as a client component with the <code>use client</code> directive at the top of the file. This directive is how the bundler identifies <code>CounterProvider</code> as a client component and treats it accordingly in the RSC payload.</p>
<p>We can use <code>useState</code> in <code>CounterProvider</code> only because we&rsquo;ve declared it as a client component.</p>
<p>Similarly, we can access the <code>counterVal</code> and <code>setCounterVal</code> in child components, <strong>but only if those children are client components</strong>.</p>

```typescript
"use client";

const SearcheableToDoList: React.FC<PropsWithChildren> = ({ children }) => {
  const { counterVal, setCounterVal } = useContext(CounterProviderContext);

  return (
    <div className="flex flex-col gap-2">
      <div className="flex gap-2">
        <button
          className="bg-white text-black"
          onClick={() => setCounterVal(counterVal + 1)}
        >
          Counter
        </button>
        <CounterDisplay />
      </div>
      <div className="flex flex-col gap-2">{children}</div>
    </div>
  );
};

export default SearcheableToDoList;
```

<p>Because <code>SearcheableToDoList</code> is a client component, we can access <code>counterVal</code> and <code>setCounterVal</code> via <code>useContext</code>.</p>
<p>The same can be said of <code>CounterDisplay</code>. As long as it is declared as a client component, we can use <code>counterVal</code> and <code>setCounterVal</code>. That&rsquo;s true even when <code>CounterDisplay</code> is a child of the <code>ToDoList</code> server component.</p>

```typescript
"use client";

const CounterDisplay = () => {
  const { counterVal } = useContext(CounterProviderContext);

  return <span>Count is {counterVal}</span>;
};

export default CounterDisplay;
```

#### You Can Use Server Code in Server Components

Server components are rendered on the server, so we can use any server side code we'd like! For instance, we can read from the file system in `ToDoList` to return the list of filtered to-dos.

```typescript
import { promises as fs } from "fs"; // import included for clarity

type ToDoListProps = PropsWithChildren & {
  searchParams?: { [key: string]: string | string[] | undefined };
};

type ToDo = {
  id: number;
  heading: string;
  body: string;
  isFavorite: boolean;
};

const fetchData = async (searchParams: {
  [key: string]: string | string[] | undefined;
}) => {
  const file = await fs.readFile(`${process.cwd()}/src/app/data.json`, "utf8");
  const parsedJson = JSON.parse(file);
  const { data } = parsedJson;

  const headingSearch = searchParams["heading"] as string;

  const res = (data as ToDo[]).filter((item) =>
    item.heading.includes(headingSearch)
  );

  return res;
};

const ToDoList: React.FC<ToDoListProps> = async ({
  searchParams,
  children,
}) => {
  const data = await fetchData(
    searchParams as { [key: string]: string | string[] }
  );

  return (
    <div className="flex gap-4">
      <div className="flex flex-col gap-4">
        {data.map((item: ToDo) => (
          <div key={item.id} className="border border-white p-4">
            <h2 className="text-2xl">{item.heading}</h2>
            <p>{item.body}</p>
          </div>
        ))}
      </div>
      <div>{children}</div>
    </div>
  );
};

export default ToDoList;
```

<p>When <code>SearchField</code> updates the query parameters, the <code>searchParams</code> passed to <code>Search</code> are updated and passed to <code>ToDoList</code>. We then search the file system using <code>fs.readFile</code> and filter out the results based on the provided query parameters.</p>
<p>ℹ️ <em>Sidenote: This works for our example, but there&rsquo;s a bit of nuance here with Next.js caching behavior that may cause issues if you try something similar in production. Check out this <a href="https://github.com/vercel/next.js/discussions/47227#discussioncomment-5342500">GitHub discussion</a> and the <a href="https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic">Next.js docs</a> for more information.</em></p>
<p>After we&rsquo;ve fetched our data and populated the component, the resulting RSC payload is streamed down to the client. Notably, this means that <strong>JavaScript used within your server component (including imports) does not get added to the bundle on your front-end</strong>!</p>
<p>For completeness, here&rsquo;s the <code>SearchField</code> component code:</p>

```typescript
const SearchField = () => {
  const router = useRouter();
  const pathname = usePathname();

  const [searchText, setSearchText] = useState("");

  const searchTextTimeout: ReturnType<typeof setTimeout> = setTimeout(() => null, 500);
  const searchTextTimeoutRef = useRef<ReturnType<typeof setTimeout>>(searchTextTimeout);

  useEffect(() => {
    clearTimeout(searchTextTimeoutRef.current);

    // this is just a debounce so we don't update query params on every keystroke
    searchTextTimeoutRef.current = setTimeout(() => {
      router.push(
        !!searchText?.length ? `${pathname}/?heading=${searchText}` : pathname
      );
    }, 500);
  }, [searchText, searchTextTimeoutRef, router, pathname]);

  return (
    <div>
      <input
        className="text-black"
        onChange={(e) => setSearchText(e.target.value)}
      />
    </div>
  );
};
```

## What Are the Advantages of React Server Components?

Using server components means your JavaScript bundle size will not scale with the size of your codebase. Couple this with the fact that server components don’t require hydration and you get a shortened time-to-interactive and a reduction in page load times.

That reduced bundle size means client machines don’t need to download as much JavaScript. Additionally, executing JavaScript on the server is often more efficient for the end-user than executing it on the client (especially for mobile devices). Both of these points lead to improved user experiences for Next.js v13 and up.

Another interesting point is that executing fetches on the server can allow developers to more easily leverage caching. Next.js already <a href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating">handles caching out-of-the-box</a> and I’m curious to see if the wider adoption of RSC reduces the need to combine React with solutions like <a href="https://www.apollographql.com/docs/apollo-server/">Apollo Server</a> and <a href="https://www.apollographql.com/docs/react/">Apollo Client</a>. While there are other benefits to these tools, RSC could provide similar caching behavior without the need to invest in a GraphQL solution.

Combining React Server Components and <code>Suspense</code> (along with traditional SSR) should also go a long way toward <a href="https://web.dev/case-studies/economic-times-inp">improving interaction to next paint (INP) for Next.js applications</a>.

📣 **Important**: As state above, RedwoodJS very recently added RSC support. That team also emphasized the overlap in functionality between RSC and GraphQL.

## What are the Disadvantages of React Server Components?

The main disadvantage of React Server Components, in my mind, is the significant increase in complexity.

A portion of this complexity should fade as React developers get accustomed to the new patterns necessitated by RSC. But as currently implemented, I <em>do</em> think RSC reduces the overall ergonomics of React – <strong>especially on any page with multiple nested client/server components and contexts.</strong>

Another disadvantage lies with RSC support. Since Next.js is the only framework supporting React Server Components, <strong>you’re stuck with it for now</strong>. And since Next.js works best when deployed to Vercel, some might also argue that narrows your choice of hosting providers.

Outside of JavaScript frameworks, there is a known <a href="https://nextjs.org/docs/app/building-your-application/styling/css-in-js">issue with CSS-in-JS</a> libraries including <code>emotion</code> and <code>styled-components</code>. That problem isn’t insurmountable, but will complicate incremental adoption for large, established code bases. Poor server component support by other libraries will also have a similar effect.

## Are React Server Components Production Ready?

My answer here would be a solid <strong>“yes, but…”</strong>.

If you’re using Next.js or plan to use Next.js, then <strong>React Server Components are production ready</strong>. There are definitely rough edges in the Next.js implementation, but I don’t think that’s a show stopper.

That being said, I suspect that greenfield projects will have an easier time adopting RSC since they can pick and choose compatible libraries. Established codebases may find it very time consuming to update their existing code to cooperate with RSCs, especially given the dearth of libraries supporting it.

ℹ️ <em>Sidenote: If you want more insight on this, check out <a href="https://nickmccurdy.com/arewerscyet/">Are we RSC yet?</a>.
</em>

If you are not using Next.js and do not plan to, I would personally advise against implementing RSC into production code until support has improved.

## Open Questions About React Server Components

In writing this article, I began forming some questions that I don’t yet have the answer to. These include:
<ul>
 	<li>How much will the combination of <a href="https://youtu.be/qOQClO3g8-Y?si=PkSs-h0D9stWjfvO">React Forget</a> and React Server Components improve React performance overall? Will they impact or compliment one another at all?</li>
 	<li>How will React Server Components work with <a href="https://expo.dev/">Expo</a> and React Native?</li>
 	<li>How does <a href="https://turbo.build/pack">Turbopack</a> fit into this? Will it bring RSC functionality to other frameworks?</li>
</ul>
If you know anything about these topics, please feel free to let me know! I’d love to learn from you.

## <h2>Further Resources and Special Thanks</h2>
Thanks for sticking with me until the end of a long article! Here are a few additional resources I came across if you’d like to learn more about React Server Components:
<ul>
 	<li><a href="https://remix.run/blog/remix-v2">Remix v2</a> (blog post)</li>
 	<li><a href="https://vercel.com/blog/understanding-react-server-components">Understanding React Server Components</a></li>
 	<li><a href="https://youtu.be/tJY1zrW35q8?si=T5BfTwMXuEo921NQ">Qwik vs. React Server Components w/ Miško Hevery: Servers, Signals, and Performance</a></li>
 	<li><a href="https://www.mux.com/blog/what-are-react-server-components">Everything I wish I knew before moving 50,000 lines of code to React Server Components</a></li>
 	<li><a href="https://app-router.vercel.app/context">Next.js client context demo</a></li>
 	<li><a href="https://www.contentful.com/blog/react-server-components-concepts-and-patterns/">React Server Components: Concepts and Patterns</a></li>
</ul>
I’d also like to extend my thanks to multiple people who provided feedback and pointed me toward resources while writing this article. Thank you for the help and I hope this was an enjoyable read!

_Learn more about how The Gnar [builds React applications](https://www.thegnar.com/software-development/react-development-js)_