Server and Client Components

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.

Server Components

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.

Why Server Components?

Server Components (RFC) 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. However, the app directory does still require JavaScript.

When a route is loaded, the Next.js and React runtime will be loaded, which is cacheable and predictable in size. This runtime does not increase in size as your application grows. Further, the runtime is asynchronously loaded, enabling your HTML from the server to be progressively enhanced on the client.

Additional JavaScript is only added as client-side interactivity is needed in your application through the use of Client Components.

Client Components

Client Components are rendered on the client. With Next.js, Client Components can also be pre-rendered on the server and hydrated on the client.

Convention

To use a Client Component, create a file inside app and add the "use client" directive at the top of the file (before any imports).

app/Counter.js
'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.

When to use Server vs. Client Components?

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 ComponentClient 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

Third-party packages

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:

app/gallery.js
'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:

app/page.js
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:

app/carousel.js
'use client';

import { AcmeCarousel } from 'acme-carousel';

export default AcmeCarousel;

Now, you can use <Carousel /> directly within a Server Component:

app/page.js
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.

Data Fetching

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.

Passing props from Server to Client Components (Serialization)

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 the pages directory where the boundary is between getStaticProps/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.

Keeping Server-Only Code out of Client Components (Poisoning)

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:

lib/data.js
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:

lib/data.js
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.

Context

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.

Using context in Client Components

All of the context APIs are fully supported within Client Components:

app/sidebar.js
'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:

app/layout.js
import { createContext } from 'react';

// 🔴 createContext is not supported in Server Components
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:

app/theme-provider.js
'use client';

import { createContext } from 'react';

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:

app/layout.js
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.

Rendering third-party context providers in 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:

app/layout.js
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:

app/providers.js
'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.

Sharing data between Server Components

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:

utils/database.js
export const db = new DatabaseConnection(...);
app/users/layout.js
import { db } from "@utils/database";

export async function UsersLayout() {
  let users = await db.query(...);
  // ...
}
app/users/[id]/page.js
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.

Sharing fetch requests between Server Components

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.

Moving Client Components to the Leaves

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.

app/layout.js
// 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>
    </>
  );
}

Importing Server Components into Client 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:

app/ClientComponent.js
'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 />
    </>
  );
}

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:

app/page.js
// ✅ 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.

For example, the <ClientLayout /> component will accept the <ServerPage /> component as its child:

app/dashboard/layout.js
'use client';

// The Dashboard Layout is a Client Component
export default function ClientLayout({ children }) {
  // Can use useState / useEffect here
  return (
    <>
      <h1>Layout</h1>
      {children}
    </>
  );
}
app/dashboard/page.js
// The Dashboard Page is a Server Component that will be
// passed to Dashboard Layout
export default function ServerPage() {
  return (
    <>
      <p>Page</p>
    </>
  );
}

API Reference