We recommend reading the Rendering Fundamentals page before continuing.
Server and Client Components allow developers to build applications that span the server and client, combining the rich interactivity of client-side apps with the improved performance of traditional server rendering.
This page will go through the differences between Server and Client Components and how to use them in your Next.js application.
All components inside the app
directory are React Server Components by default, including special files and colocated components. This allows you to automatically adopt Server Components with no extra work, and achieve great performance out of the box.
React Server Components allow developers to better leverage server infrastructure. For example, large dependencies that previously would impact the JavaScript bundle size on the client can instead remain entirely on the server, leading to improved performance.
Server Components make writing a React application feel similar to PHP or Ruby on Rails, but with the power and flexibility of React for templating UI.
When a route is loaded with Next.js, the initial HTML is rendered on the server. This HTML is then progressively enhanced in the browser, allowing the client to take over the application and add interactivity, by asynchronously loading the Next.js and React client-side runtime.
With Server Components, the initial page load is faster, and the client-side JavaScript bundle size is reduced. The base client-side runtime is cacheable and predictable in size, and does not increase as your application grows. Additional JavaScript is only added as client-side interactivity is used in your application through Client Components.
Client Components enable you to add client-side interactivity to your application. In Next.js, they are prerendered on the server and hydrated on the client. You can think of Client Components as how Next.js 12 and previous versions worked (i.e. the pages/
directory).
A component becomes a Client Component when using the "use client"
directive at the top of the file (before any imports).
These components (and files) can be placed anywhere inside your application. They do not need to be in app/
, specifically.
For example, you might want a components/
directory. However, the app/
directory enables you to colocate components with pages, which was not previously possible in the pages/
directory.
'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
You only need to mark components as 'use client'
when they use client hooks such as useState
or useEffect
. It's best to leave components that do not depend on client hooks without the directive so that they can automatically be rendered as a Server Component when they aren't imported by another Client Component. This helps ensure the smallest amount of client-side JavaScript. Learn more.
To simplify the decision between Server and Client Components, we recommend using Server Components (default in the app
directory) until you have a need to use a Client Component.
This table summarizes the different use cases for Server and Client Components:
What do you need to do? | Server Component | Client Component |
---|---|---|
Fetch data. Learn more. | ✅ | ⚠️ |
Access backend resources (directly) | ✅ | ❌ |
Keep sensitive information on the server (access tokens, API keys, etc) | ✅ | ❌ |
Keep large dependencies on the server / Reduce client-side JavaScript | ✅ | ❌ |
Add interactivity and event listeners (onClick() , onChange() , etc) | ❌ | ✅ |
Use State and Lifecycle Effects (useState() , useReducer() , useEffect() , etc) | ❌ | ✅ |
Use browser-only APIs | ❌ | ✅ |
Use custom hooks that depend on state, effects, or browser-only APIs | ❌ | ✅ |
Use React Class components | ❌ | ✅ |
Server and Client Components can be interleaved in the same component tree. Behind the scenes, React will merge the work of both environments.
However, in React, there's a restriction around importing Server Components inside Client Components because Server Components might have server-only code (e.g. database or filesystem utilities).
For example, importing a Server Component in a Client Component will not work:
'use client';
// ❌ This pattern will not work. You cannot import a Server
// Component into a Client Component
import ServerComponent from './ServerComponent';
export default function ClientComponent() {
return (
<>
<ServerComponent />
</>
);
}
Instead, you can pass a Server Component as a child or prop of a Client Component. You can do this by wrapping both components in another Server Component. For example:
'use client';
export default function ClientComponent({children}) {
return (
<>
{children}
</>
);
}
// ✅ This pattern works. You can pass a Server Component
// as a child or prop of a Client Component.
import ClientComponent from "./ClientComponent";
import ServerComponent from "./ServerComponent";
// Pages are Server Components by default
export default function Page() {
return (
<ClientComponent>
<ServerComponent />
</ClientComponent>
);
}
With this pattern, React will know it needs to render <ServerComponent />
on the server before sending the result (which doesn't contain any server-only code) to the client. From the Client Component's perspective, its child will be already rendered.
This pattern is already applied in layouts and pages with the children
prop so you don't have to create an additional wrapper component.
Props passed from the Server Components to Client components need to be serializable. This means that values such as functions, Dates, etc, cannot be passed directly to client components.
Where is the Network Boundary?
In the
app
directory, the network boundary is between Server Components and Client Components. This is different from thepages
directory where the boundary is betweengetStaticProps
/getServerSideProps
and Page Components. Data fetched inside Server Components do not need to be serialized as it doesn't cross the network boundary unless it is passed to a Client Component. Learn more about data fetching with Server Components.
Since JavaScript modules can be shared between both Server and Client Components, it's possible for code that was only ever intended to be run on the server to sneak its way into the client.
For example, take the following data-fetching function:
export async function getData() {
let res = await fetch("https://external-service.com/data", {
headers: {
authorization: process.env.API_KEY,
},
});
return res.json();
}
At first glance, it appears that getData
works on both the server and the client. But because the environment variable API_KEY
is not prefixed with NEXT_PUBLIC
, it's a private variable that can only be accessed on the server. Next.js replaces private environment variables with the empty string in client code to prevent leaking secure information.
As a result, even though getData()
can be imported and executed on the client, it won't work as expected. And while making the variable public would make the function work on the client, it would leak sensitive information.
So, this function was written with the intention that it would only ever be executed on the server.
To prevent this sort of unintended client usage of server code, we can use the server-only
package to give other developers a build-time error if they ever accidentally import one of these modules into a Client Component.
To use server-only
, first install the package:
npm install server-only
Then import the package into any module that contains server-only code:
import "server-only";
export async function getData() {
let resp = await fetch("https://external-service.com/data", {
headers: {
authorization: process.env.API_KEY,
},
});
return resp.json();
}
Now, any Client Component that imports getData()
will receive a build-time error explaining that this module can only be used on the server.
The corresponding package client-only
can be used to mark modules that contain client-only code – for example, code that accesses the window
object.
To improve the performance of your application, we recommend moving Client Components to the leaves of your component tree where possible.
For example, you may have a Layout that has static elements (e.g. logo, links, etc) and an interactive search bar that uses state.
Instead of making the whole layout a Client Component, move the interactive logic to a Client Component (e.g. <SearchBar />
) and keep your layout as a Server Component. This means you don't have to send all the component Javascript of the layout to the client.
// SearchBar is a Client Component
import SearchBar from './SearchBar';
// Logo is a Server Component
import Logo from './Logo';
// Layout is a Server Component by default
export default function Layout({ children }) {
return (
<>
<nav>
<Logo />
<SearchBar />
</nav>
<main>{children}</main>
</>
);
}
The "use client"
directive is a new React feature that was introduced as part of Server Components. Since Server Components are so new, third-party packages in the ecosystem are just beginning to add it to components that use client-only features like useState
, useEffect
and createContext
.
Today, many components from npm packages that use client-only features do not yet have the directive. These third-party components will work as expected within your own Client Components, since they themselves have the "use client"
directive, but they won't work within Server Components.
For example, let's say you've installed the hypothetical acme-carousel
package which has an <AcmeCarousel />
component. This component uses useState
, but it doesn't yet have the "use client"
directive.
If you use <AcmeCarousel />
within a Client Component, it will work as expected:
'use client';
import { useState } from 'react';
import { AcmeCarousel } from 'acme-carousel';
export default function Gallery() {
let [isOpen, setIsOpen] = useState(false);
return (
<div>
<button onClick={() => setIsOpen(true)}>View pictures</button>
{/* 🟢 Works, since AcmeCarousel is used within a Client Component */}
{isOpen && <AcmeCarousel />}
</div>
);
}
However, if you try to use it directly within a Server Component, you'll see an error:
import { AcmeCarousel } from 'acme-carousel';
export default function Page() {
return (
<div>
<p>View pictures</p>
{/* 🔴 Error: `useState` can not be used within Server Components */}
<AcmeCarousel />
</div>
);
}
This is because Next.js doesn't know <AcmeCarousel />
is using client-only features.
To fix this, you can wrap third-party components that rely on client-only features in your own Client Components:
'use client';
import { AcmeCarousel } from 'acme-carousel';
export default AcmeCarousel;
Now, you can use <Carousel />
directly within a Server Component:
import Carousel from './carousel';
export default function Page() {
return (
<div>
<p>View pictures</p>
{/* 🟢 Works, since Carousel is a Client Component */}
<Carousel />
</div>
);
}
We don't expect you to need to wrap most third-party components since it's likely you'll be using them within Client Components. However, one exception is provider components, since they rely on React state and context, and are typically needed at the root of an application. Learn more about third-party context providers below.
Although it's possible to fetch data in Client Components, we recommend fetching data in Server Components unless you have a specific reason for fetching data on the client. Moving data fetching to the server leads to better performance and user experience.
Learn more about data fetching.
Most React applications rely on context to share data between components, either directly via createContext
, or indirectly via provider components imported from third-party libraries.
In Next.js 13, context is fully supported within Client Components, but it cannot be created or consumed directly within Server Components. This is because Server Components have no React state (since they're not interactive), and context is primarily used for rerendering interactive components deep in the tree after some React state has been updated.
We'll discuss alternatives for sharing data between Server Components, but first, let's take a look at how to use context within Client Components.
All of the context APIs are fully supported within Client Components:
'use client';
import { createContext, useContext, useState } from 'react';
const SidebarContext = createContext();
export function Sidebar() {
const [isOpen, setIsOpen] = useState();
return (
<SidebarContext.Provider value={{ isOpen }}>
<SidebarNav />
</SidebarContext.Provider>
);
}
function SidebarNav() {
let { isOpen } = useContext(SidebarContext);
return (
<div>
<p>Home</p>
{isOpen && <Subnav />}
</div>
);
}
However, context providers are typically rendered near the root of an application to share global concerns, like the current theme. Because context is not supported in Server Components, trying to create a context at the root of your application will cause an error:
import { createContext } from 'react';
// 🔴 createContext is not supported in Server Components
export const ThemeContext = createContext({});
export default function RootLayout({ children }) {
return (
<html>
<body>
<ThemeContext.Provider value="dark">
{children}
</ThemeContext.Provider>
</body>
</html>
);
}
To fix this, create your context and render its provider inside of a Client Component:
'use client';
import { createContext } from 'react';
export const ThemeContext = createContext({});
export default function ThemeProvider({ children }) {
return (
<ThemeContext.Provider value="dark">
{children}
</ThemeContext.Provider>
);
}
Your Server Component will now be able to directly render your provider since it's been marked as a Client Component:
import ThemeProvider from './theme-provider';
export default function RootLayout({ children }) {
return (
<html>
<body>
<ThemeProvider>{children}</ThemeProvider>
</body>
</html>
);
}
With the provider rendered at the root, all other Client Components throughout your app will be able to consume this context.
Note: You should render providers as deep as possible in the tree – notice how
ThemeProvider
only wraps{children}
instead of the entire<html>
document. This makes it easier for Next.js to optimize the static parts of your Server Components.
Third-party npm packages often include Providers that need to be rendered near the root of your application. If these providers include the "use client"
directive, they can be rendered directly inside of your Server Components. However, since Server Components are so new, many third-party providers won't have added the directive yet.
If you try to render a third-party provider that doesn't have "use client"
, it will cause an error:
import { ThemeProvider } from 'acme-theme';
export default function RootLayout({ children }) {
return (
<html>
<body>
{/* 🔴 Error: `createContext` can't be used in Server Components */}
<ThemeProvider>{children}</ThemeProvider>
</body>
</html>
);
}
To fix this, wrap third-party providers in your own Client Component:
'use client';
import { ThemeProvider } from 'acme-theme';
import { AuthProvider } from 'acme-auth';
export function Providers({ children }) {
return (
<ThemeProvider>
<AuthProvider>
{children}
</AuthProvider>
</ThemeProvider>
);
}
Now, you can import and render <Providers />
directly within your root:
import { Providers } from './providers';
export default function RootLayout({ children }) {
return (
<html>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
With the providers rendered at the root, all the components and hooks from these libraries will work as expected within your own Client Components.
Once a third-party library has added "use client"
to its client code, you'll be able to remove the wrapper Client Component.
Since Server Components are not interactive and therefore do not read from React state, you don't need the full power of context to share data. You can use native JavaScript patterns like global singletons within module scope if you have common data that multiple Server Component need to access.
For example, a module can be used to share a database connection across multiple components:
export const db = new DatabaseConnection(...);
import { db } from "@utils/database";
export async function UsersLayout() {
let users = await db.query(...);
// ...
}
import { db } from "@utils/database";
export async function DashboardPage() {
let user = await db.query(...);
// ...
}
In the above example, both the layout and page need to make database queries. Each of these components shares access to the database by importing the @utils/database
module.
When fetching data, you may want to share the result of a fetch
between a page
or layout
and some of its children components. This is an unnecessary coupling between the components and can lead to passing props
back and forth between components.
Instead, we recommend colocating data fetching alongside the component that consumes the data. fetch
requests are automatically deduped in Server Components, so each route segment can request exactly the data it needs without worrying about duplicate requests. Next.js will read the same value from the fetch
cache.