Next.js Discord

Discord Forum

Server components misunderstanding

Answered
Bengal posted this in #help-forum
Open in Discord
BengalOP
Hi everyone, I am sure I am not the first one to come up with this question, so if you already have detailed answers reference, just comment me and I will refer to them, otherwise let's continue.

I am confused about Server and Client components nesting and hwo the Boundary separates them. Docs have detailed explanation of how they are working, but still they have confusing parts.

From the Docs - Defining multiple use client entry points: You can define multiple "use client" entry points in your React Component tree. This allows you to split your application into multiple client bundles. However, "use client" doesn't need to be defined in every component that needs to be rendered on the client. Once you define the boundary, all child components and modules imported into it are considered part of the client bundle.

Also from docs - Check the first screenshot.

THE CONFUSION - As per my understanding and docs, nested elements ( child components and imported modules ) for the client component will be automatically considered as a client component by Next. On the other side, check the 2nd screenshot, and it appears you are still able to render server component inside a client component via children. My question - WHat's the single source of truth? I need to wrap my whole next.js app with i18n and QueryClientProvider ( tanstack ) providers. What will be the result eventually?
Answered by LuisLl
If you wrap your root (or whatever part of your React tree) in a Client Provider, this provider takes children right? Well, children will remain a Server Component as long as it was already a Server Component. Same applies if it’s already a Client Component, will remain a Client Component.

This is because children can take anything, have in mind that we have two environments now, the server and the client, you don’t really know which component will replace children (I’ll explain why at the end) until react builds the VirtualDOM.

You can see children as a slot, at the moment of rendering your components, children holds a reference to something (any ReactNode) that will fill that slot, but you don’t actually own that component.

You don’t own it because you received it via props (since children is a prop). You did not declare nor imported the component (children) within that file marked with “use client” (in this case where you have the Provider) which means the only thing the Provider can do is render whatever it got passed in the slot children. It can't decide where React runs.

The environment which actually owns the component will decide whether this will render as a Server or Client component.

Have in mind that in Next.js all components are Server Components by default, and you opt out of it by defining client boundaries with “use client”. When you import a component, either Server Component (default) or Client Component inside a file with the “use client” directive, this component will turn into a Client Component too, its code (and all that it owns) will be sent to the client.

Maybe such component did not even need any client-side features or interactivity, but by the mere fact of being imported into the client boundary now it’s part of the client bundle.
View full answer

19 Replies

@Bengal Hi everyone, I am sure I am not the first one to come up with this question, so if you already have detailed answers reference, just comment me and I will refer to them, otherwise let's continue. I am confused about Server and Client components nesting and hwo the Boundary separates them. Docs have detailed explanation of how they are working, but still they have confusing parts. From the Docs - `Defining multiple use client entry points: You can define multiple "use client" entry points in your React Component tree. This allows you to split your application into multiple client bundles. However, "use client" doesn't need to be defined in every component that needs to be rendered on the client. Once you define the boundary, all child components and modules imported into it are considered part of the client bundle.` Also from docs - Check the first screenshot. THE CONFUSION - As per my understanding and docs, nested elements ( child components and imported modules ) for the client component will be automatically considered as a client component by Next. On the other side, check the 2nd screenshot, and it appears you are still able to render server component inside a client component via children. My question - WHat's the single source of truth? I need to wrap my whole next.js app with i18n and QueryClientProvider ( tanstack ) providers. What will be the result eventually?
wdym by source of truth?

client components become interactive and the data rendered in it can be changed

server components remain static and whatever is there during rendering remains there for the lifetime of the component

server components can be passed as children to client components but it will be the same as
<ClientComponent data={await getData()} />

the client component cannot change the value passed to its data prop and the getData call cannot access the state or anything that goes on inside the client component
@joulev wdym by source of truth? client components become interactive and the data rendered in it can be changed server components remain static and whatever is there during rendering remains there for the lifetime of the component server components can be passed as children to client components but it will be the same as tsx <ClientComponent data={await getData()} /> the client component cannot change the value passed to its `data` prop and the `getData` call cannot access the state or anything that goes on inside the client component
BengalOP
The fact that the docs mention 2 different things ( Correct me if I am wrong ) about client components.
1. - Once you define the boundary, all child components and modules imported into it are considered part of the client bundle.
2. The right screenshot ensures you can render server component inside client component and it is still a server component.

I hope it''s clear for you now why I am confused.
@Bengal Hi everyone, I am sure I am not the first one to come up with this question, so if you already have detailed answers reference, just comment me and I will refer to them, otherwise let's continue. I am confused about Server and Client components nesting and hwo the Boundary separates them. Docs have detailed explanation of how they are working, but still they have confusing parts. From the Docs - `Defining multiple use client entry points: You can define multiple "use client" entry points in your React Component tree. This allows you to split your application into multiple client bundles. However, "use client" doesn't need to be defined in every component that needs to be rendered on the client. Once you define the boundary, all child components and modules imported into it are considered part of the client bundle.` Also from docs - Check the first screenshot. THE CONFUSION - As per my understanding and docs, nested elements ( child components and imported modules ) for the client component will be automatically considered as a client component by Next. On the other side, check the 2nd screenshot, and it appears you are still able to render server component inside a client component via children. My question - WHat's the single source of truth? I need to wrap my whole next.js app with i18n and QueryClientProvider ( tanstack ) providers. What will be the result eventually?
When they say “use client” defines a boundary what they mean is that by writing “use client” at the top of a file you’re basically opening a door to the client. With it you tell the Next.js bundler to ship all this chunk of code to the client (or multiple chunks if you have multiple “use client” directives).

However, "use client" doesn't need to be defined in every component that needs to be rendered on the client. Once you define the boundary, all child components and modules imported into it are considered part of the client bundle.

Why is this not necessary and still be able use of client-side only features?

Because you already crossed the door to the client, why would you need to open a new door if you’re already out there?

All imports and whatever you own within that scope become part of the client bundle you sent through the door.

It doesn’t matter where the component ends up being rendered in the actual DOM tree in the browser, it matters where React runs your react code, that’s why you can pass Server Components down as props and keep them on the Server: they were rendered by React on the server, doesn’t matter where they end up appearing in the actual DOM tree.
@LuisLl When they say *“use client” defines a boundary* what they mean is that by writing **“use client”** at the top of a file you’re basically *opening a door to the client*. With it you tell the *Next.js bundler* to ship all this chunk of code to the client (or multiple chunks if you have multiple “use client” directives). > However, "use client" doesn't need to be defined in every component that needs to be rendered on the client. Once you define the boundary, all child components and modules imported into it are considered part of the client bundle. *Why is this not necessary and still be able use of client-side only features?* Because you already *crossed the door to the client*, why would you *need* to open a new door if you’re already out there? All imports and whatever you *own* within that scope become part of the client bundle you sent through the door. It doesn’t matter where the component ends up being rendered in the actual DOM tree in the browser, it matters **where React runs your react code**, that’s why *you can pass Server Components down as props* and keep them on the Server: they were rendered by React on the server, doesn’t matter where they end up appearing in the actual DOM tree.
BengalOP
Thanks for the thorough explanation. I still have one more question. Ok, I know that Server Components are rendered in the server, if I wrap my root with a context provider, does it mean that nested Server Components will also be a part of client bundle regardless of where they have been rendered initially?
The mental model behind Server Components states in favor of decreased client bundle size as well besides the security, SEO and other useful things.

I believe this is the last piece of puzzle for me to get the point
If you wrap your root (or whatever part of your React tree) in a Client Provider, this provider takes children right? Well, children will remain a Server Component as long as it was already a Server Component. Same applies if it’s already a Client Component, will remain a Client Component.

This is because children can take anything, have in mind that we have two environments now, the server and the client, you don’t really know which component will replace children (I’ll explain why at the end) until react builds the VirtualDOM.

You can see children as a slot, at the moment of rendering your components, children holds a reference to something (any ReactNode) that will fill that slot, but you don’t actually own that component.

You don’t own it because you received it via props (since children is a prop). You did not declare nor imported the component (children) within that file marked with “use client” (in this case where you have the Provider) which means the only thing the Provider can do is render whatever it got passed in the slot children. It can't decide where React runs.

The environment which actually owns the component will decide whether this will render as a Server or Client component.

Have in mind that in Next.js all components are Server Components by default, and you opt out of it by defining client boundaries with “use client”. When you import a component, either Server Component (default) or Client Component inside a file with the “use client” directive, this component will turn into a Client Component too, its code (and all that it owns) will be sent to the client.

Maybe such component did not even need any client-side features or interactivity, but by the mere fact of being imported into the client boundary now it’s part of the client bundle.
Answer
@LuisLl If you wrap your root (or whatever part of your React tree) in a Client Provider, this *provider* takes children right? Well, children will remain a Server Component **as long as it was already a Server Component**. Same applies if it’s already a Client Component, will remain a Client Component. This is because children can take *anything*, have in mind that we have two environments now, the server and the client, you *don’t really know which component will replace children* (I’ll explain why at the end) until react builds the VirtualDOM. You can see *children* as a **slot**, at the moment of rendering your components, **children holds a reference to something (any ReactNode) that will fill that slot**, but you don’t actually *own* that component. You don’t *own* it because you received it via props (since children is a prop). You **did not declare nor imported** the component (children) within that file marked with “use client” (in this case where you have the Provider) which means the only thing the Provider can do is render whatever it got passed in the **slot** *children*. It can't decide where React runs. The environment which actually *owns* the component will decide whether this will render as a Server or Client component. Have in mind that in Next.js all components are Server Components by default, and you opt out of it by defining *client boundaries* with “use client”. When you *import* a component, either Server Component (default) or Client Component inside a file with the “use client” directive, this component will turn into a Client Component too, its code (and all that it *owns*) will be sent to the client. Maybe such component did not even need any *client-side features or interactivity*, but by the mere **fact of being imported into the client boundary now it’s part of the client bundle**.
BengalOP
To summarize of what you are explaining, does the client bundle include any rendered server component? I kind of confuse it. We say that all the imported components and child components of the client component will be included in the client bundle at the end. I know I kind of misunderstand it as it would be unnecessary to say that server components decrease the client bundle size
This is because children can take anything, have in mind that we have two environments now, the server and the client, you don’t really know which component will replace children

When React starts rendering your components, it first renders your Server Components, traverses the tree and when it encounters a “client boundary” it skipps it, leaving Client Components to render at the end.

So now you can understand why Client Components have a slot where children will be placed. And since Server components are ready even before you start with the Client ones, when React is rendering the Server component tree, React adds references to where Client components will be placed, and sends the references along with the output of the generated tree in the RSC Payload.

By the time React renders your client components it knows which components need to fill the children slots and it just places them wherever they need to be, so how could this turn them into client components if server components were already rendered on the server before the client component wrapper was rendered?
If you do that, and the Server Component is async and does server only stuff it’ll break and throw an error
Server Components that have Server Only (that make use of async-await)features can only be passed via props to client components
@LuisLl If they are imported inside a client boundary then yes, the server component code and bundle will be sent to the client too
BengalOP
Not talking about importing. Just sending as a prop. In that case will they still be in the client bundle? Or the client bundle will only keep the reference of the server component?
@Bengal Not talking about importing. Just sending as a prop. In that case will they still be in the client bundle? Or the client bundle will only keep the reference of the server component?
No they will not be in the client bundle. When the client bundle reaches the browser it’ll hydrate your client components only, the RSC payload will have references that indicate where they need to be placed in the Tree and if they have to fill that children slot
Basically when you render components on the server you get this React Server Component payload, you’ve probably read about that. This RSC payload not only contains the output of your React components as serialized HTML, it also contains the references for where they need to be rendered, props, etc..

React takes this payload on the client and does its magic to build the Virtual DOM, placing components in the right order no matter if they’re server or client components
https://react.dev/reference/rsc/use-client
This might be a little confusing but considering you've understood the general idea you might want to read it.
@LuisLl Basically when you render components on the server you get this React Server Component payload, you’ve probably read about that. This RSC payload not only contains the output of your React components as serialized HTML, it also contains the references for where they need to be rendered, props, etc.. React takes this payload on the client and does its magic to build the Virtual DOM, placing components in the right order no matter if they’re server or client components
BengalOP
Yeah, I have read about RSC Payload. Basically it's 2 way usage of RSC Payload. On the server, Next.js utilizes it to render HTML on server, and then on the client, React uses the same RSC payload to reconcile the tree. I guess I finally got all the understanding of Server and Client components. Thanks a lot for this great conversation. Will check the source for sure to nail it better 😎
@Bengal make sure to mark the solution so others can find it:)