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 Component | Client Component | |
|---|---|---|
| Runs on | Server only | Browser, plus server for initial HTML |
| Ships to browser | Output only | Code plus output |
| State and Hooks | No | Yes |
| Event handlers | No | Yes |
| Database and filesystem | Yes | No |
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.
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.
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
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.
Frequently Asked Questions
Can a Client Component render a Server Component?
Is a Client Component also rendered on the server?
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.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.