React Server and Client Components in Next.js: Understanding the Difference

The React team introduced Server Components as an experimental feature in React 18. They allow parts of a React application to render on the server, reducing the JavaScript sent to the client and enabling more efficient data fetching.
Next.js adopted this concept and integrated it into its App Router (introduced in version 13). The framework combines React's server-rendering capabilities with its own routing, data fetching and performance optimizations.
Server Components let developers build apps that are faster, more secure and easier to maintain—while still adding interactivity through Client Components where needed.
What Are Server Components?
Server Components run exclusively on the server—they never execute in the browser and cannot use client-only features like useState, useEffect, or window.
Since they render on the server, they can securely fetch data from databases or APIs and send back only the resulting HTML to the client. This reduces bundle size and improves performance.
Key Characteristics:
- Run only on the server
- Exclude JavaScript from the client bundle
- Fetch data securely without needing API routes
- Cannot use React state hooks or browser APIs
- Can import Client Components, but Client Components cannot import them
Example:
// This is a Server Component (default) export default async function ServerComponent() { const posts = await fetchPosts(); return ( <ul> {posts.map(post => <li key={post.id}>{post.title}</li>)} </ul> ); }
By default, all components in the Next.js App Router (app/ directory) are Server Components, unless specified otherwise.
What Are Client Components?
Client Components are traditional React components that run in the browser. They're necessary when you need interactivity, state, or effects.
To mark a file as a Client Component, add this directive at the top: "use client";
Here's a common misconception: Client Components are still prerendered on the server. During the initial render, Next.js generates HTML for them on the server—just like Server Components. Once the JavaScript bundle loads in the browser, React hydrates these components, attaching event listeners and state to make them interactive.
Example:
"use client"; import { useState } from "react"; export default function Counter() { const [count, setCount] = useState(0); return ( <button onClick={() => setCount(count + 1)}> Clicked {count} times </button> ); }
Important:
- Hydration errors occur when the server-rendered HTML doesn't match what React renders in the browser—for example, when using
Math.random()orDate.now()during render. - Client Components cannot import Server Components
- However, you can pass Server Components as props to Client Components. React renders them on the server and includes them in the client-rendered tree (see below).
Combining Server and Client Components
Next.js's true power lies in combining both component types effectively. You can fetch data on the server, then pass it to a client component for interactive rendering.
Example:
// Server Component import Counter from "./Counter"; // ✅ allowed (Client Component) export default async function Page() { const user = await fetchUser(); return ( <div> <h1>Hello, {user.name}</h1> <Counter /> </div> ); }
Passing Server Components as Props
While Client Components cannot import Server Components, a Server Component can pass another Server Component as a prop to a Client Component.
This works because the server renders the server-side part before sending it to the browser.
// Server Component A export function ServerInfo() { return <p>Server time: {new Date().toISOString()}</p>; } // Client Component "use client"; export function Wrapper({ info }) { return ( <div className="wrapper"> <h2>Wrapped content:</h2> {info} </div> ); } // Server Page import { ServerInfo } from "./ServerInfo"; import { Wrapper } from "./Wrapper"; export default function Page() { return <Wrapper info={<ServerInfo />} />; }
Here's what happens:
Wrapperis a Client Component.- It does not import
ServerInfodirectly. - Instead,
ServerInfois rendered on the server and passed as a serialized React node through props.
This pattern is powerful for composition, layout customization, and partial interactivity in server-driven views.
Hydration and Common Pitfalls
Hydration is the process of React attaching interactivity to the static HTML produced by the server.
It’s an essential step — but also a common source of confusion and bugs.
Common Causes of Hydration Errors:
- Non-deterministic rendering — e.g., using
Math.random(),Date.now(), or random IDs directly in render. - Conditional rendering differences between server and client.
- Mismatched props — if server and client data diverge during hydration.
How to Avoid Them:
- Use deterministic data in components that render both server- and client-side.
- Avoid rendering dynamic values that differ between server and client.
- Keep interactivity isolated in small, well-defined Client Components.
- Keep dynamic parts in “client only scope”, like useEffect hook
Quick Comparison
| Feature | Server Component | Client Component |
|---|---|---|
| Execution | Server only | Server prerender + Browser hydration |
Can use hooks (useState, useEffect) | ❌ | ✅ |
| Can fetch data securely | ✅ | ⚠️ via API routes |
| Imports direction | ✅ Can import Client | ❌ Cannot import Server |
| Can receive Server Components as props | ✅ | ✅ |
| Bundle size impact | Minimal | Increases bundle size |
| SEO | Excellent | Also good (since prerendered) |
| Typical use | Static content, data fetching | Interactive UI, forms, animations |
Conclusion
React introduced the Server/Client component model, giving developers precise control over where and how rendering happens. Next.js enhances this with routing, data fetching, and performance optimizations.
To summarize:
- Use Server Components for data-heavy or static content.
- Use Client Components for interactivity.
- Client Components are prerendered on the server, then hydrated in the browser.
- Import flow: Server → Client ✅, Client → Server ❌.
- However, Server Components can be passed to Client Components via props ✅.
When used correctly, this architecture makes your app faster, more secure, and easier to maintain—a true win for modern React development.






