Server and Client Component Patterns in Next.js
Table of Contents When to Use Each Type Server Components Can: Client Components Can: Server Component Patterns Sharing Data Between Components Keeping Server Code Out of the Client Using Third-Party Components Using Context Providers Client Component Patterns Moving Client Components Down the Tree Passing Props from Server to Client Components Interleaving Server and Client Components Pattern to Avoid: Importing Server Components into Client Components Supported Pattern: Passing Server Components as Props When to Use Each Type Server Components Can: Fetch data directly Access backend resources (databases, internal APIs) Keep sensitive information secure (tokens, API keys) Hold large dependencies that don't need to be sent to the client Client Components Can: Add interactivity with event listeners (onClick, onChange) Use React state and lifecycle effects (useState, useEffect) Access browser-only APIs (window, localStorage) Use custom hooks that depend on state or browser APIs Use React class components Client Components need the "use client" directive at the top of their file to tell Next.js they should run on the client. Server Component Patterns Sharing Data Between Components When multiple server components need the same data, you don't need to pass props down or use context. Instead, each component can fetch the data it needs directly. Next.js automatically memoizes fetch calls, so if multiple components request the same data, the actual fetch happens only once. For non-fetch functions, use React's cache function for the same effect. Keeping Server Code Out of the Client Sometimes server-specific code might accidentally be included in client bundles, like code accessing private environment variables. To prevent this, use the server-only package: // In your server-only module import "server-only"; export async function getData() { // Code that should only run on the server const res = await fetch("https://api.example.com", { headers: { authorization: process.env.API_KEY }, }); return res.json(); } If any client component tries to import this module, you'll get a build-time error. For client-only code, use the client-only package. Using Third-Party Components Many third-party components haven't yet added the "use client" directive despite using client-only features. These will work in Client Components but fail in Server Components. The solution is to wrap these third-party components in your own Client Component: // carousel.tsx "use client"; import { Carousel } from "acme-carousel"; export default Carousel; Now you can use your wrapped component in Server Components. Using Context Providers React context doesn't work in Server Components. To use context, create your provider in a Client Component: // theme-provider.tsx "use client"; import { createContext } from "react"; export const ThemeContext = createContext({}); export default function ThemeProvider({ children }) { return {children}; } Then use it in your Server Component layout: // layout.tsx import ThemeProvider from "./theme-provider"; export default function Layout({ children }) { return ( {children} ); } Place providers as deep in the tree as possible to help Next.js optimize static parts. Client Component Patterns Moving Client Components Down the Tree To reduce JavaScript sent to the browser, move interactive parts into separate Client Components rather than making entire layouts or pages client components. Example: Keep a layout as a Server Component, but make just the interactive search bar a Client Component. Passing Props from Server to Client Components You can pass data from Server to Client Components, but the props must be serializable (can be converted to JSON). Complex objects like functions, dates, or classes won't work. If you need non-serializable data, either fetch it directly in the Client Component or use a Route Handler. Interleaving Server and Client Components You can think of your UI as a tree starting with the root layout (a Server Component). Some subtrees can be rendered on the client by adding "use client". Within client subtrees, you can still include Server Components, but there are important rules to follow. Pattern to Avoid: Importing Server Components into Client Components This doesn't work: "use client"; // ❌ Error: You cannot import a Server Component into a Client Component import ServerComponent from "./server-component"; export default function ClientComponent() { const [count, setCount] = useState(0); return ( setCount(count + 1)}>{count} ); } Supported Pattern: Passing Server Components as Props This works well: // In client-component.tsx "use client"; export default function

Table of Contents
- When to Use Each Type
- Server Components Can:
- Client Components Can:
-
Server Component Patterns
- Sharing Data Between Components
- Keeping Server Code Out of the Client
- Using Third-Party Components
- Using Context Providers
-
Client Component Patterns
- Moving Client Components Down the Tree
- Passing Props from Server to Client Components
- Interleaving Server and Client Components
- Pattern to Avoid: Importing Server Components into Client Components
- Supported Pattern: Passing Server Components as Props
When to Use Each Type
Server Components Can:
- Fetch data directly
- Access backend resources (databases, internal APIs)
- Keep sensitive information secure (tokens, API keys)
- Hold large dependencies that don't need to be sent to the client
Client Components Can:
- Add interactivity with event listeners (
onClick
,onChange
) - Use React state and lifecycle effects (
useState
,useEffect
) - Access browser-only APIs (
window
,localStorage
) - Use custom hooks that depend on state or browser APIs
- Use React class components
Client Components need the "use client"
directive at the top of their file to tell Next.js they should run on the client.
Server Component Patterns
Sharing Data Between Components
When multiple server components need the same data, you don't need to pass props down or use context. Instead, each component can fetch the data it needs directly.
Next.js automatically memoizes fetch calls, so if multiple components request the same data, the actual fetch happens only once. For non-fetch functions, use React's cache
function for the same effect.
Keeping Server Code Out of the Client
Sometimes server-specific code might accidentally be included in client bundles, like code accessing private environment variables. To prevent this, use the server-only
package:
// In your server-only module
import "server-only";
export async function getData() {
// Code that should only run on the server
const res = await fetch("https://api.example.com", {
headers: { authorization: process.env.API_KEY },
});
return res.json();
}
If any client component tries to import this module, you'll get a build-time error. For client-only code, use the client-only
package.
Using Third-Party Components
Many third-party components haven't yet added the "use client"
directive despite using client-only features. These will work in Client Components but fail in Server Components.
The solution is to wrap these third-party components in your own Client Component:
// carousel.tsx
"use client";
import { Carousel } from "acme-carousel";
export default Carousel;
Now you can use your wrapped component in Server Components.
Using Context Providers
React context doesn't work in Server Components. To use context, create your provider in a Client Component:
// theme-provider.tsx
"use client";
import { createContext } from "react";
export const ThemeContext = createContext({});
export default function ThemeProvider({ children }) {
return <ThemeContext.Provider value="dark">{children}ThemeContext.Provider>;
}
Then use it in your Server Component layout:
// layout.tsx
import ThemeProvider from "./theme-provider";
export default function Layout({ children }) {
return (
<html>
<body>
<ThemeProvider>{children}ThemeProvider>
body>
html>
);
}
Place providers as deep in the tree as possible to help Next.js optimize static parts.
Client Component Patterns
Moving Client Components Down the Tree
To reduce JavaScript sent to the browser, move interactive parts into separate Client Components rather than making entire layouts or pages client components.
Example: Keep a layout as a Server Component, but make just the interactive search bar a Client Component.
Passing Props from Server to Client Components
You can pass data from Server to Client Components, but the props must be serializable (can be converted to JSON). Complex objects like functions, dates, or classes won't work.
If you need non-serializable data, either fetch it directly in the Client Component or use a Route Handler.
Interleaving Server and Client Components
You can think of your UI as a tree starting with the root layout (a Server Component). Some subtrees can be rendered on the client by adding "use client"
.
Within client subtrees, you can still include Server Components, but there are important rules to follow.
Pattern to Avoid: Importing Server Components into Client Components
This doesn't work:
"use client";
// ❌ Error: You cannot import a Server Component into a Client Component
import ServerComponent from "./server-component";
export default function ClientComponent() {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(count + 1)}>{count}button>
<ServerComponent />
>
);
}
Supported Pattern: Passing Server Components as Props
This works well:
// In client-component.tsx
"use client";
export default function ClientComponent({ children }) {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(count + 1)}>{count}button>
{children}
>
);
}
// In page.tsx (a Server Component)
import ClientComponent from "./client-component";
import ServerComponent from "./server-component";
export default function Page() {
return (
<ClientComponent>
<ServerComponent />
ClientComponent>
);
}
This approach allows both components to render independently → the Server Component renders on the server before the Client Component renders on the client.
You're not limited to just the children
prop. You can use any prop to pass Server Component content to a Client Component.