Nesting Server and Client Components

Pro Members Only

This lesson is available if you have an active subscription.

Alternatively, some member might be able to gift it to you.

If you already have a subscription, you can sign in.

Nesting Server and Client Components

Subscription Required

You must have an active subscription to access this content.
If you already have a subscription, you can sign in.

Kinds of Components

There are three kinds of NextJS components

  • Server Components: They can use server only features (like async/await, server node modules etc.)
  • Client Components: Marked with the 'use client;' directive. They can use client only features (like event handlers etc.)
  • Unmarked Components: They do not depend on server only or client only features. They do not have the 'use client;' directive.

Server Component Rendering

When rendering from a server component you can render all kinds of components as children. Note that unmarked components render as server components.

This is demonstrated below.

app/page.tsx
app/ui/server.tsx
app/ui/client.tsx
app/ui/unmarked.tsx
import { ServerComponent } from "./ui/server";
import { ClientComponent } from "./ui/client";
import { UnmarkedComponent } from "./ui/unmarked";

export default function ServerPage() {
console.log("Page: Server");
return (
<>
<h1>Server Page</h1>
<ServerComponent />
<ClientComponent />
<UnmarkedComponent />
</>
);
}

Client Component Rendering

When rendering from a client component you cannot render a server component. Note that unmarked components render as client components.

This is demonstrated below.

app/page.tsx
app/ui/server.tsx
app/ui/client.tsx
app/ui/unmarked.tsx
"use client";

import { ClientComponent } from "./ui/client";
import { UnmarkedComponent } from "./ui/unmarked";

export default function ClientPage() {
console.log("Page: Client");
return (
<>
<h1>Client Page</h1>
<ClientComponent />
<UnmarkedComponent />
{/* You CANNOT render a ServerComponent here */}
</>
);
}

Rendering a Server Component inside a Client Component

In order to render a server component inside a client component, you need to first render it on the server and then pass it as a prop to the client component.

This is demonstrated below.

app/page.tsx
app/server.tsx
app/client.tsx
import { ClientComponent } from './client';
import { ServerComponent } from './server';

export default function ServerPage() {
console.log("Page: Server");
return (
<>
<h1>Server Page</h1>
<ClientComponent>
<ServerComponent />
</ClientComponent>
</>
);
}

Reference Guide

  • Guiding Principles
    • Server components can only be rendered on the server
    • Client components can be rendered from server or client components
    • Unmarked components render...
      • as a server component from a server component
      • as a client component from a client component
  • Practical Approach
    • From a server component...
      • server component - renders as a server component
      • client component - renders as a client component
      • unmarked component - renders as a server component
    • From a client component...
      • client component - render as a client component
      • unmarked component - renders as client component
      • server components need to be rendered on the server and passed in as a prop
javascript
typescript
react
playwright

Enjoy free content straight from your inbox 💌

No spam, unsubscribe at any time.

Transcript

00:00

Perhaps the most common confusion I find amongst next year's developers is how they can mix and nest react server and client components. So this lesson will answer a number of questions which will completely clarify the situation. For this lesson, we will create a few components. The first one will be a server component in which we'll use the FS module. This will be an asy component, and within the component we will render out the contents of the Readme MD file. All of these components will also do a consult log statement so that we can see where these components are getting rendered.

00:33

The next component will be a client component. Now, there is nothing client specific about this component. The fact that it has the use client directive means that this will be something that will be hydrated on the client. And finally, something that is often overlooked is an unmarked component. This component doesn't have any specific client side or service side functionality and its behavior will change depending upon how we render it. Let's first talk about rendering from a server component. Starting from a server component gives you the most flexibility in terms of rendering.

01:06

So let's create a simple page within our next year's application. Now by default, in the absence of the use client directive, next year's will try to render it as a server component. Now, this page being a server component itself, of course, if you bring in a server component and render it out, it should work perfectly fine. And if you jump to the browser, that is exactly what we find. Now, a key thing to note over here is that this component is not hydrated on the client. In fact, if you open up the console, we see no log statements. However, if you look at the server terminal, you can see that the page as well

01:40

as the component was rendered on the server. Next, let's bring in a client component. We render it out the same way we rendered out the server component and once more, as you would expect, this will work perfectly fine, and this can be verified by visiting the page on the browser, and you can see that the server and the client component were rendered perfectly fine. However, the client component will be hydrated on the client. That is the rendering function will run on the client, and we can verify that by looking at the browser console. Now of course, as we saw in our use client lesson on the server side, all three components are going to render

02:14

and return their HTMO as a part of the response. Now let's talk about the unmarked component. We bring it in just like the server and the client components and render it out as a part of the server page component. Now, as you would expect, this will also work perfectly fine, but let's think about where this component is actually going to get rendered. Since this component is unmarked and being rendered from a server component, it'll actually not go through the process of hydration. It'll only render on the server, and therefore in the browser console console, we see no log statements for this component and we only find them within the server terminal.

02:48

So in summary, a server component can render the server client or unmarked components. The child's server components will render as server components. The client components will render as client components and unmarked components will actually render as server components. Now let's look at the same components. When we are rendering from a client component, we create a sample next JS page, but this time we use the use client directive for this page, and this tells next JS that the page component we are exporting is going to be a client component. Let's start off by first bringing in our

03:20

sample client component. We bring it in and then render it out as a part of our page. Now, as you would expect, this works perfectly fine. However, the thing to note over here is that both of these components are rendered on the server as well as being hydrated on the client. Now let's add our unmarked component into the mix. We bring it in and then render it out. Now this also works perfectly fine. As we can see, it is a part of the rendered ui, and just like before, it is initially being rendered on the server and then sent to the client.

03:53

A question that I have for you at this point is, is this component going to be considered a server component or a client component? The answer is that it is going to be considered a client component in this particular case, and we can verify that by looking at the browser console. You can see that it was hydrated on the client. And the reason is because we are rendering within a client component, anything that we render from our client component is going to be considered a client component. Now, let's try our final component over here, which is a server component. We bring it in and then try to render it out as a part

04:27

of our client component page. And this is something that is actually not allowed by React. We cannot render a React server component from within a client component, and this error is caught by next js. If you look at the browser, you can see that it has failed to compel because of course FS is not a module that exists within the browser. This means that a server component cannot be directly rendered from a client component. Even though we cannot directly render a server component from a client, we can render a server component within a section of a client component.

05:00

We can achieve this by first rendering the server component on the server and then passing it as a prop to the client component. So we have the server component that we've been using till now, and our objective is to render it within a client component. To demonstrate how we can achieve that, let's create a client component. We have the used client directive, and then we have the client component body. And within a portion of this ui, our objective is to render out that server component. As we have seen, this is not something that we can do directly. If you bring it in over here, you will get

05:32

that error FS module not found. However, let's start our journey from a server component. So we bring in the client component and the server component, and we create a simple server component page. And we know that within this component we can render out the client component as well as the server component. So what if we render the server component on the server and then pass it to the client component as a prop? To do this, we jump Into our client component and add a prop to accept the rendered server component. And then within the portion where we want to render the server component,

06:04

we simply render out the past in prop. Now all that is left to do is that we need to pass in the server component as a prop to the client component. And to do that, we simply render out the server component as a part of the server page component and then pass the rendered result as a prop to the client component. And now because the server component is being returned from the server page component, this is actually going to work perfectly fine. We can see that the server component has been rendered into a section within the client component. Now, make no mistake,

06:35

the server component is not being rendered on the client, and we can verify that by opening up the browser console. You can see that the only thing that is being hydrated is the client component. And if you look at the server terminal, the server page and the server component are only being rendered on the server. Now, this example was designed to make everything crystal clear, but we can just as easily jump into the client component and instead of a named prop, we can accept components as a children prop. And now instead of passing in the server component as a prop, we can even render it out

07:08

as a standard nested react component. And while it might trick your eyes into thinking that we are rendering a server component within a client component, that is not the case. The component is still being rendered on the server and then being passed as a prop to the client. And once more, we can verify that by looking at the browser console, the server component is not being hydrated on the client and it only shows up in the server terminal. With all these practical examples under our belt, let's do a recap of what we've learned. Here are your practical guiding principles when mixing

07:41

server and client components within next year. And you can use these principles to check the sanity of any piece of code that you will encounter. First up, the server components can only be rendered on the server. Client components can be rendered from the server or client components, and unmarked components should be considered a chameleon. When rendered from a server component, they will render as a server component, and when rendered from a client component, they will render as a client component. From a practical standpoint, let's look at what happens when we are rendering from a server component.

08:14

A child server component will render as a server component. A client component will render as a client component, and unmarked component will be the chameleon and will render as a server component. Similarly, when starting from a client component, child client components will render as a client component as they always do. Unmarked components will be a chameleon and will render as a client component. And as we know, server components cannot be directly rendered as children of client components and the first need to be rendered on the server and then passed in as a prop to the client component.