Sharing Components Between Server and Client in NextJS
In Next.js App Router, components are split into Server Components and Client Components. Server Components run on the server, keeping secrets safe, while Client Components run in the browser, handling interactivity. The challenge is sharing data and UI between them without breaking the rules of each environment.
What are Server and Client Components?
Server Components are the default in Next.js App Router. They run only on the server, fetching data from databases, using API keys, and keeping sensitive logic out of the browser. They don’t send JavaScript to the client, reducing bundle size.
Client Components run on both the server (for the initial HTML) and the client (for interactivity). They’re marked with the ‘use client’ directive at the top of the file. They can use useState, useEffect, event handlers, and browser APIs like localStorage and window.
How to Pass Data from Server to Client via Props
The simplest way to share data between Server and Client Components is to pass it as props. The Server Component fetches the data, and the Client Component receives it and handles interactivity.
Here’s a basic example. A page (Server Component) fetches a post and passes the like count to a LikeButton (Client Component):
// app/post/[id]/page.jsx (Server Component)
import LikeButton from '@/app/ui/like-button';
import { getPost } from '@/lib/data';
export default async function PostPage({ params }) {
const { id } = await params;
const post = await getPost(id);
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
<LikeButton likes={post.likes} postId={post.id} />
</div>
);
}
The Server Component fetches data on the server. The Client Component receives plain values (likes, postId) and manages state and events. This pattern keeps data fetching on the server and interactivity on the client.
How to Pass Server Components as Children to Client Components
You can pass a Server Component as the children prop (or any prop) to a Client Component. The Server Component still renders on the server. The Client Component receives the rendered output, not the component code.
This is useful when you want a Client Component to wrap or control the layout of server-rendered content. For example, a modal that shows server-fetched data:
// app/ui/modal.jsx (Client Component)
'use client';
import { useState } from 'react';
export default function Modal({ children }) {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button onClick={() => setIsOpen(true)}>Open</button>
{isOpen && (
<div className="modal-overlay">
<div className="modal-content">{children}</div>
</div>
)}
</>
);
}
Cart is a Server Component that fetches cart data. It’s passed as children to Modal, which is a Client Component. The server renders Cart first. The RSC Payload includes the rendered result. The client receives that output and displays it inside the modal.
What Props Are Allowed Between Server and Client
Props passed from Server Components to Client Components must be serializable. React serializes them into the RSC Payload so they can be sent to the client.
Allowed Types:
- Strings, numbers, booleans
- null and undefined
- Plain objects (no functions, no class instances)
- Arrays of serializable values
- JSX (Server Components as children or other props)
- Server Actions (functions with ‘use server’)
Not Allowed:
- Functions (except Server Actions)
- Date objects
- Class instances
- Symbols
- Map, Set, WeakMap, WeakSet
Real-World Examples
Sharing components between Server and Client Components is a common challenge in Next.js App Router. By following the patterns and rules outlined in this guide, you can share data and UI between Server and Client Components without breaking the rules of each environment.
Conclusion
Sharing components between Server and Client Components is a powerful feature in Next.js App Router. By understanding the rules and patterns outlined in this guide, you can create complex and scalable applications that take advantage of the strengths of both Server and Client Components.
Remember to keep data fetching on the server and interactivity on the client. Use props to pass data between Server and Client Components, and use Server Components as children to Client Components to wrap or control the layout of server-rendered content.
With practice and experience, you’ll become proficient in sharing components between Server and Client Components in Next.js App Router.








