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

Published: (December 30, 2025 at 06:00 PM EST)
4 min read
Source: Dev.to

Source: Dev.to

Introduction

The React team introduced Server Components as an experimental feature in React 18. They let parts of a React application render on the server, reducing the JavaScript sent to the client and enabling more efficient data fetching.

Next.js adopted this concept in 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

  • Run exclusively on the server – they never execute in the browser.
  • Cannot use client‑only features such as useState, useEffect, or window.
  • Can securely fetch data from databases or APIs and send back only the resulting HTML.
  • Exclude JavaScript from the client bundle, which reduces bundle size and improves performance.
  • Can import Client Components, but Client Components cannot import Server Components.
// 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 marked otherwise.

Client Components

Client Components are traditional React components that run in the browser. They are required when you need interactivity, state, or side‑effects.

To mark a file as a Client Component, add the "use client" directive at the top:

"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>
  );
}

Key points

  • Rendered on the server for the initial HTML (prerender), then hydrated in the browser.
  • Can use React state hooks (useState, useEffect, etc.) and browser APIs.
  • Cannot import Server Components directly, but can receive them as props.

Composing Server and Client Components

Passing Server Components to Client Components

A Server Component can render another Server Component and pass it as a prop to a Client Component. The server renders the node, serializes it, and the client receives it as a React element.

// Server Component
export function ServerInfo() {
  return <div>Server time: {new Date().toISOString()}</div>;
}

// Client Component (Wrapper)
"use client";
export function Wrapper({ info }) {
  return (
    <section>
      ## Wrapped content:
      {info}
    </section>
  );
}

// Server Page
import { ServerInfo } from "./ServerInfo";
import { Wrapper } from "./Wrapper";

export default function Page() {
  return <Wrapper info={<ServerInfo />} />;
}

Using a Client Component inside a Server Component

// Server Component (page)
import Counter from "./Counter"; // ✅ allowed (Client Component)

export default async function Page() {
  const user = await fetchUser();
  return (
    <section>
      <h1>Hello, {user.name}</h1>
      <Counter />
    </section>
  );
}

Hydration

Hydration is the process where React attaches interactivity to the static HTML produced by the server. Common pitfalls include:

  • Non‑deterministic rendering (e.g., Math.random(), Date.now()) that yields different markup on server vs. client.
  • Conditional rendering differences between server and client.
  • Mismatched props when server and client data diverge.

Best practices

  • Use deterministic data in components that render on both sides.
  • Keep interactivity isolated in small, well‑defined Client Components.
  • Place dynamic logic inside useEffect or other client‑only scopes.

Comparison

FeatureServer ComponentClient Component
ExecutionServer onlyServer prerender + Browser hydration
Can use React state hooks (useState, useEffect)
Secure data fetching✅ (direct)⚠️ (via API routes)
Import direction✅ Can import Client Components❌ Cannot import Server Components
Can receive Server Components as props
Bundle size impactMinimalIncreases bundle size
SEOExcellentAlso good (prerendered)
Typical useStatic content, data‑heavy renderingInteractive UI, forms, animations

Summary

  • Server Components are ideal for data‑heavy or static content; they run only on the server, keep the client bundle small, and improve SEO.
  • Client Components provide interactivity; they are prerendered on the server and hydrated in the browser.
  • Import flow follows Server → Client (allowed) but Client → Server is prohibited.
  • Passing Server Components as props to Client Components enables powerful composition while preserving the benefits of both rendering models.

When used correctly, this architecture makes your Next.js app faster, more secure, and easier to maintain—a true win for modern React development.

Back to Blog

Related posts

Read more »

The Web Ecosystem Civil War

markdown !Javadhttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads...

React Coding Challenge : Card Flip Game

React Card Flip Game – Code tsx import './styles.css'; import React, { useState, useEffect } from 'react'; const values = 1, 2, 3, 4, 5; type Card = { id: numb...