Server Components vs Client Components: What Runs Where?

Server Components render only on the server and send output, while Client Components run in the browser and own state, effects, and event handlers.

7 min read

Server Components vs Client Components comes down to where each one runs. Server Components render only on the server and send their output to the browser, while Client Components run in the browser and are the only components that can use state, effects, and event handlers. Components are Server Components by default, and a 'use client' marker makes a module a Client Component.

The core difference

Where a component runs decides what it can do and what the user downloads.

Server ComponentClient Component
Runs onServer onlyBrowser, plus server for initial HTML
Ships to browserOutput onlyCode plus output
State and HooksNoYes
Event handlersNoYes
Database and filesystemYesNo

A Server Component can query a database and read files, but it cannot keep state or handle a click. A Client Component can do all the interactive work, but it cannot reach the server's filesystem directly.

It is the module tree, not the render tree

Client or Server status is decided by the module a component is defined in, not by where it appears on the page. A component with no 'use client' marker is a Server Component when used from server code, and a Client Component when imported inside a client module.

The same module can even run in both places. A shared FancyText component has no directive, so its output is sent to the browser when a Server Component uses it, and its code is bundled when a Client Component imports it.

App.jsxApp.jsx
export default function FancyText({ title, text }) {
  return title ? <h1>{text}</h1> : <p>{text}</p>;
}

The definition stays the same. What changes is which environment evaluates each usage, which is why the React docs describe Server and Client Components in terms of usages rather than definitions.

How they compose

A Server Component can render a Client Component and pass serializable props or JSX children. The reverse is not true by import: a Client Component cannot import a Server Component, because that would force server code into the client bundle.

The escape hatch is children. A Server Component renders a Client Component and passes the Server Component's JSX inside it, so the server still renders the child while the client renders the wrapper.

App.jsxApp.jsx
import Expandable from "./Expandable";
 
async function Notes() {
  const notes = await db.notes.getAll();
  return (
    <div>
      {notes.map((note) => (
        <Expandable key={note.id}>
          <p>{note}</p>
        </Expandable>
      ))}
    </div>
  );
}

Here Notes renders on the server and Expandable renders on the client. Each note paragraph is still server-rendered and passed through as children, so the client only receives the interactive wrapper.

What can cross the boundary

Props passed from a Server Component to a Client Component must be serializable, because they cross from the server into the client bundle.

  • Allowed: strings, numbers, booleans, null, arrays, plain objects, Date values, JSX, Promises, and Server Functions.
  • Not allowed: plain functions, classes, class instances, and symbols that are not globally registered.

A prop that cannot be serialized fails at the boundary. Keep the data shape simple, and pass rich behavior as a Server Function or JSX instead of an inline callback. Serialization is why the server can send finished note text but never the live function that produced it.

Which should you use?

Keep a component as a Server Component unless it needs a client-only feature. Add 'use client' only for interactivity, browser APIs, or third-party libraries that require the client.

When in doubt, leave it on the server: less code ships, and the page reaches first paint sooner. Move a piece to the client only when it actually needs the browser.

Start from React Server Components Explained for the base model, and see how the use client directive works for the exact rules of the boundary. For mutations, React Server Functions and Server Actions run on the server while staying callable from client code.

Rune AI

Rune AI

Key Insights

  • Server Components run only on the server and send output.
  • Client Components run in the browser and own state, effects, and handlers.
  • Client or Server status follows the module tree, not the render tree.
  • Props crossing the boundary must be serializable.
  • Add use client only for interactivity or browser APIs.
RunePowered by Rune AI

Frequently Asked Questions

Can a Client Component render a Server Component?

Not by importing it. Importing would pull server code into the client bundle. A Server Component can pass JSX as children into a Client Component instead.

Is a Client Component also rendered on the server?

Yes, for the initial HTML. The framework server-renders Client Components for the first paint, then the browser hydrates them and runs them from then on.

Conclusion

Server Components run only on the server and send output, while Client Components run in the browser and own the interactive features. Use a Server Component by default and add use client only where the browser is required.