Modern React development is no longer limited to rendering everything in the browser. With React Server Components, developers can split an application so that some components run in a server environment while other components handle interaction in the browser.
This introduces two important concepts:
- Server Components
- Client Components
Although both are React components, they are designed for different jobs.
A Server Component is ideal for tasks such as reading server-side data, accessing backend resources, reducing JavaScript sent to the browser, and rendering non-interactive content.
A Client Component is used when the interface needs browser APIs, state, effects, event handlers, or direct user interaction.
The most important point is that modern React applications do not need to choose only one. In many cases, the best architecture combines Server Components for data and static UI with Client Components for interactive features. React documents Server Components as stable in React 19, while noting that the lower-level APIs used by frameworks and bundlers to implement them are still evolving. (React)
In this complete guide, you will learn what Server Components and Client Components are, how they work, their differences, examples, performance benefits, limitations, and when to use each one.
What Are React Server Components?
React Server Components are components that render in a server-side environment rather than becoming part of the browser’s client-side JavaScript bundle.
Despite the name, a Server Component does not necessarily have to run on a traditional web server for every request.
Depending on your framework and application architecture, Server Components can run:
At build time
or
On the server for a request
React explains that Server Components can render before bundling in an environment separate from the browser application. They can therefore access resources available to that server environment, including files and backend services. (React)
A simple Server Component could look like this:
export default async function Products() {
const products = await getProducts();
return (
<div>
{products.map((product) => (
<article key={product.id}>
<h2>{product.name}</h2>
<p>${product.price}</p>
</article>
))}
</div>
);
}
This component can retrieve information before producing the UI.
Most importantly, the component’s implementation does not need to become browser JavaScript.
What Are Client Components?
Client Components are React components that can participate in interactive browser behavior.
They are needed when your component uses functionality such as:
useStateuseEffect- event handlers
- browser APIs
- local interactive state
- DOM APIs
- interactive third-party libraries
For example:
"use client";
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
The "use client" directive creates a client boundary. React’s documentation explains that exports from a module marked with "use client" can be rendered as Client Components and can use browser interaction features that Server Components cannot. (React)
Server Components vs Client Components: Quick Comparison
| Feature | Server Components | Client Components |
|---|---|---|
| Main Environment | Server/build environment | Browser-capable client boundary |
useState | No | Yes |
useEffect | No | Yes |
| Event handlers | No | Yes |
| Browser APIs | No | Yes |
| Direct server resource access | Yes | No |
Async component with await | Yes | Not in the same Server Component style |
| JavaScript added to client bundle | Component code itself does not need to be shipped | Yes |
| User interaction | No direct interaction | Yes |
| Data fetching | Excellent | Possible |
| Database access | Can be direct where framework allows | Should use server/API boundary |
| Secrets | Can remain server-side | Must not contain private secrets |
| Best use | Data-heavy, non-interactive UI | Interactive UI |
The key difference is not simply where HTML appears.
Instead, the important distinction is where the component code executes and what capabilities it has.
Why Were Server Components Introduced?
Traditional React applications often send a large amount of JavaScript to the browser.
A common client-side architecture looks like:
Browser loads JavaScript
↓
React initializes
↓
Component renders
↓
API request starts
↓
Server returns JSON
↓
React renders data
This approach works well. However, the browser may need to download and execute code that does not actually require interaction.
For example, imagine a blog article.
The application may need to:
- Download JavaScript.
- Execute React.
- Send an API request.
- Retrieve the article.
- Render the article.
Yet most of the article is simply content.
Server Components allow more work to happen before that code reaches the user’s browser.
Conceptually:
Server
↓
Read Data
↓
Render Server Component
↓
Send Result
↓
Browser Displays UI
As a result, less JavaScript may need to be sent and executed on the client. React specifically lists reduced client code as one of the major advantages of Server Components. (React)
Understanding the Server and Client Environments
Before comparing the two component types, it helps to understand their environments.
Server Environment
The server can usually access:
Database
Filesystem
Environment variables
Private services
Internal APIs
Authentication services
Backend code
For example:
export default async function UserPage() {
const user = await database.users.findFirst();
return <h1>{user.name}</h1>;
}
The browser does not need direct database credentials.
Instead, the server performs the operation.
Client Environment
The client is the user’s browser.
It has access to things such as:
window
document
localStorage
navigator
DOM events
browser APIs
For example:
"use client";
import { useState } from "react";
export default function Menu() {
const [open, setOpen] = useState(false);
return (
<button onClick={() => setOpen(!open)}>
{open ? "Close" : "Open"} Menu
</button>
);
}
This component needs to respond after the user clicks.
Therefore, browser-side behavior is necessary.
How Server Components Work
A simplified React Server Component architecture looks like:
Server Components
↓
Rendered on Server
↓
React Server Component Payload
↓
Client
↓
React Combines Server + Client Components
↓
UI
Frameworks implementing Server Components send a special representation of the rendered component tree rather than simply turning every Server Component into browser JavaScript.
Next.js describes this as the React Server Component Payload, which includes the result of Server Components together with references showing where Client Components belong. (Next.js)
What Is the React Server Component Payload?
It is useful to understand that Server Components are not just traditional HTML templates.
React can produce a specialized representation containing information about:
Rendered Server Components
Client Component placeholders
Component relationships
Serializable values
The client can then combine this information with Client Component JavaScript.
Conceptually:
Server Component
↓
RSC Payload
↓
Browser
↓
Client Component JavaScript
↓
Combined React UI
This lets Server and Client Components exist in the same React component tree.
Server Components Are Not the Same as SSR
This is one of the most important concepts beginners often misunderstand.
React Server Components and Server-Side Rendering are not the same thing.
Traditional SSR generally works like this:
React Component
↓
Server renders HTML
↓
HTML sent to browser
↓
JavaScript downloaded
↓
Hydration
↓
Interactive React app
With Server Components, the component’s implementation does not have to become part of the client-side JavaScript bundle.
Therefore:
SSR
≠
Server Components
They can work together, but they solve different problems.
Can Client Components Be Server-Rendered?
Yes, and this is another important distinction.
The term Client Component does not always mean:
This component’s initial HTML can only be created in the browser.
In frameworks such as Next.js, Client Components can participate in prerendering or server rendering for the initial page.
However, their JavaScript still needs to be available on the client so that interactive behavior works.
Therefore, think of "use client" primarily as a client JavaScript boundary, not simply as a command saying “never render this on a server.”
Creating a Server Component
In an environment where Server Components are supported, you normally do not add a special "use server" directive to make a component a Server Component.
For example:
export default async function BlogPosts() {
const posts = await getPosts();
return (
<section>
<h1>Latest Posts</h1>
{posts.map((post) => (
<article key={post.id}>
<h2>{post.title}</h2>
</article>
))}
</section>
);
}
An important correction for beginners is:
"use client"
→ Client boundary
"use server"
→ Server Functions
No "use server" directive is required simply to define a Server Component.
React’s Server Component documentation explicitly warns about this common misconception. (React)
Creating a Client Component
To establish a Client Component boundary, add:
"use client";
at the top of the module.
For example:
"use client";
import { useState } from "react";
export default function LikeButton() {
const [likes, setLikes] = useState(0);
return (
<button onClick={() => setLikes(likes + 1)}>
Like ({likes})
</button>
);
}
Because this component uses state and a click handler, it needs client-side capabilities.
Why Does useState Require a Client Component?
State exists across interactions.
Imagine:
Count = 0
User clicks button
Count = 1
The component must remain reactive in the browser after the initial page has loaded.
Server Components, by contrast, do not persist in browser memory like interactive client components.
React explains that Server Components cannot use most Hooks and cannot maintain their own interactive state in the browser. (React)
Therefore:
const [count, setCount] = useState(0);
belongs inside a Client Component.
Why Can’t Server Components Use onClick?
Consider:
<button onClick={handleClick}>
Buy Now
</button>
The click occurs on the user’s device.
Therefore, something in the browser must listen for that event.
Server Components do not provide client-side event handlers directly.
React specifically lists handlers such as onClick as functionality that requires Client Components. (React)
Server Component Data Fetching
Data fetching is one of the strongest use cases for Server Components.
For example:
export default async function Products() {
const response = await fetch(
"https://example.com/api/products"
);
const products = await response.json();
return (
<ul>
{products.map((product) => (
<li key={product.id}>
{product.name}
</li>
))}
</ul>
);
}
In frameworks that support this pattern, the Server Component can wait for data before continuing its rendering.
React Server Components support async components and await directly on the server. (React)
Direct Database Access
One major advantage of Server Components is that server-only operations can remain on the server.
For example:
import { db } from "@/lib/database";
export default async function Users() {
const users = await db.user.findMany();
return (
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name}
</li>
))}
</ul>
);
}
Conceptually:
Server Component
↓
Database
↓
Data
↓
Rendered Result
↓
Browser
This can eliminate unnecessary client-to-API-to-server hops for some architectures.
However, direct database access depends on the framework and deployment environment being used.
Server Components and Sensitive Information
Suppose your backend needs:
Database credentials
Private API keys
Internal services
Secret tokens
These should never be bundled into browser JavaScript.
Server Components can help keep server-only code and dependencies on the server.
However, developers must still be careful about the data they return.
A secret should not be rendered into props or output merely because the component itself runs on the server.
Props Between Server and Client Components
Server Components can render Client Components.
For example:
import LikeButton from "./LikeButton";
export default async function Post({ id }) {
const post = await getPost(id);
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
<LikeButton postId={post.id} />
</article>
);
}
Here:
Post
→ Server Component
LikeButton
→ Client Component
This is an excellent architecture.
The server handles data and content, while the browser handles interaction.
Props Must Cross the Server-Client Boundary
When data moves from a Server Component into a Client Component, React must be able to transfer that value across the boundary.
Therefore, props generally need to be serializable using the supported React Server Component serialization model. React documents supported values such as primitives, arrays, maps, sets, dates, plain objects, promises, and Server Functions, while arbitrary class instances and ordinary functions are not supported. (React)
For most beginner applications, think of props such as:
strings
numbers
booleans
plain objects
arrays
as straightforward values to pass across the boundary.
Combining Server and Client Components
The real power of this architecture comes from combining both component types.
Consider an e-commerce page:
ProductPage
│
├── ProductInformation
├── ProductDescription
├── Reviews
│
└── AddToCartButton
A sensible architecture could be:
ProductPage
→ Server Component
ProductInformation
→ Server Component
ProductDescription
→ Server Component
Reviews
→ Server Component
AddToCartButton
→ Client Component
Only the button needs browser interaction.
Therefore, there is little reason to make the entire product page client-side.
Example: Product Page
Server Component
import AddToCartButton from "./AddToCartButton";
export default async function ProductPage({ id }) {
const product = await getProduct(id);
return (
<main>
<h1>{product.name}</h1>
<p>{product.description}</p>
<strong>${product.price}</strong>
<AddToCartButton
productId={product.id}
/>
</main>
);
}
Client Component
"use client";
import { useState } from "react";
export default function AddToCartButton({
productId,
}) {
const [added, setAdded] = useState(false);
function handleAdd() {
setAdded(true);
// Add product to cart
}
return (
<button onClick={handleAdd}>
{added ? "Added" : "Add to Cart"}
</button>
);
}
This separation gives each component one clear responsibility.
Keep Client Components Small When Possible
Suppose your page contains:
Header
Article
Author
Comments
Share Button
Only the Share Button requires browser interaction.
Instead of making the complete page a Client Component, you can isolate the interactive section:
Page — Server
├── Header — Server
├── Article — Server
├── Author — Server
├── Comments — Server
└── ShareButton — Client
This technique can reduce how much JavaScript becomes part of the client bundle.
Next.js recommends placing the client boundary around the smaller interactive parts of a component tree rather than unnecessarily moving the entire interface to the client. (Next.js)
The "use client" Boundary
Consider:
"use client";
import Header from "./Header";
import Search from "./Search";
export default function Navbar() {
return (
<>
<Header />
<Search />
</>
);
}
Once a module becomes part of a client boundary, its client-side dependency graph must also be available to the browser.
Therefore, avoid placing:
"use client";
high in your component tree unless necessary.
Instead of:
Whole Page → Client
prefer:
Page → Server
Small Interactive Feature → Client
when your architecture allows it.
Server Components Reduce Client JavaScript
Imagine a product page that uses:
Markdown parser
Database library
Formatting library
Backend utilities
If those operations happen inside Server Components, their server-only implementation does not need to be part of the browser bundle.
React lists this reduction in client-side code as one of the primary benefits of Server Components. (React)
This can improve:
- download size
- JavaScript parsing
- JavaScript execution
- client resource usage
Actual performance improvements still depend on the application’s architecture and implementation.
Server Components Can Be Async
A Server Component can be declared with:
async function
For example:
export default async function Profile() {
const user = await getUser();
return (
<section>
<h1>{user.name}</h1>
</section>
);
}
React can suspend while the Promise resolves.
This makes server data loading feel natural.
React also supports streaming this architecture together with Suspense boundaries. (React)
Suspense and Server Components
Suppose your page contains:
Article
Comments
The article loads quickly, while comments take longer.
Instead of blocking everything, you might structure the page with Suspense:
import { Suspense } from "react";
export default function Page() {
return (
<>
<Article />
<Suspense fallback={<p>Loading comments...</p>}>
<Comments />
</Suspense>
</>
);
}
This lets slower parts of the interface load separately.
Therefore, users can potentially see important content earlier.
What Can Server Components Do?
Server Components are particularly useful for:
Fetching Data
const products = await getProducts();
Reading Files
readFile(...)
where the runtime provides filesystem access.
Accessing Databases
db.products.findMany()
Using Server-Only Libraries
Libraries that should never run in a browser can remain server-side.
Heavy Non-Interactive Processing
For example:
Markdown conversion
Content processing
Server-side formatting
Rendering Non-Interactive UI
Examples include:
Articles
Product descriptions
Category lists
Documentation
Static profile information
What Can’t Server Components Do?
Server Components cannot directly use interactive browser functionality.
For example:
useState()
is not appropriate for normal Server Component interactive state.
Likewise:
useEffect()
is a client-side effect Hook.
Server Components also cannot directly use browser-specific APIs such as:
window
document
localStorage
navigator
because they run outside the browser.
Finally, they cannot directly define regular browser event handlers such as:
onClick
onChange
onInput
These behaviors require a Client Component boundary.
What Can Client Components Do?
Client Components can handle browser interaction.
Examples include:
State
const [open, setOpen] = useState(false);
Effects
useEffect(() => {
// browser-side effect
}, []);
Event Handling
<button onClick={handleClick}>
Browser APIs
localStorage.getItem("theme")
Interactive Forms
Search inputs
Validation
Dynamic fields
Dropdowns
UI Interactions
Modal
Tabs
Dropdown
Slider
Carousel
Drag and drop
When Should You Use a Server Component?
Use Server Components when your component mainly:
- retrieves backend data
- displays static or server-generated content
- accesses server resources
- accesses a database
- performs server-only work
- does not require browser state
- does not require browser event handlers
Examples include:
Blog article
Product list
Product details
Documentation page
Category page
Order history
Server-generated profile
When Should You Use a Client Component?
Use a Client Component when you need:
useStateuseEffect- event handlers
- browser APIs
- client-side stores
- interactive third-party packages
- DOM interaction
Examples include:
Like button
Search field
Dropdown
Modal
Tabs
Theme switcher
Shopping cart controls
Interactive chart
Form editor
Common Server Component Example
Suppose you need to show products.
export default async function Products() {
const products = await fetchProducts();
return (
<section>
{products.map((product) => (
<ProductCard
key={product.id}
product={product}
/>
))}
</section>
);
}
If there is no interaction, a Server Component may be enough.
Common Client Component Example
Now suppose each product has a favorite button.
"use client";
import { useState } from "react";
export default function FavoriteButton() {
const [favorite, setFavorite] = useState(false);
return (
<button
onClick={() => setFavorite(!favorite)}
>
{favorite ? "Remove Favorite" : "Add Favorite"}
</button>
);
}
Only this small interactive component needs client-side state.
Example Component Tree
A modern application might look like this:
Page — Server
│
├── Navbar — Server
│ └── MobileMenu — Client
│
├── ProductList — Server
│ ├── ProductCard — Server
│ │ └── FavoriteButton — Client
│
└── Footer — Server
This architecture keeps most content server-driven while preserving interaction exactly where it is needed.
Server Components and SEO
Server-rendered content can be useful for search-engine-visible pages because important content can be available without depending entirely on a client-side data fetch after initial load.
Examples include:
Blog articles
Product descriptions
Documentation
Category pages
Landing pages
However, SEO depends on more than simply whether a component is a Server Component.
You must also consider:
- metadata
- URL structure
- content quality
- semantic HTML
- performance
- crawlability
- structured data
Therefore, Server Components can support an SEO-friendly architecture, but they are not an automatic SEO solution.
Server Components and Performance
Server Components may improve performance by reducing how much component JavaScript needs to be downloaded by the browser.
For example:
Traditional Client-Heavy Page
Content JS
Product JS
Formatting JS
Interactive JS
↓
Browser
With an appropriate Server Component architecture:
Server-only rendering logic
↓
Server
Small interactive JS
↓
Browser
As a result, the browser may have less JavaScript to download and execute.
Nevertheless, application performance still depends on:
- network latency
- server response time
- caching
- database speed
- images
- third-party scripts
- client bundle size
- rendering architecture
Server Components vs Client Components for Data Fetching
Both environments can retrieve data.
However, the correct approach depends on when and why the data is needed.
Server Component
export default async function Products() {
const products = await getProducts();
return <ProductList products={products} />;
}
This works well when data is needed to initially render the page.
Client Component
"use client";
import { useEffect, useState } from "react";
export default function Search() {
const [results, setResults] = useState([]);
// fetch based on interaction
}
Client fetching is useful when data depends on interactive browser behavior.
Examples include:
Live search
Infinite scroll
User-triggered refresh
Client-only dashboards
Real-time interaction
Server Components vs TanStack Query
These technologies are not necessarily replacements for each other.
Server Components can load data on the server for rendering.
TanStack Query is particularly useful for managing server state inside interactive client-side interfaces.
A possible architecture is:
Initial Page Data
↓
Server Components
Interactive / Changing Client Data
↓
TanStack Query
For example, a product page could render product details on the server while an interactive reviews section uses client-side querying.
The best approach depends on how dynamic the data is.
Server Components vs Traditional API Routes
Traditionally:
Browser
↓
API Route
↓
Backend
↓
Database
With some Server Component architectures:
Server Component
↓
Database
This can remove an unnecessary internal HTTP request when both operations are already running inside your server environment.
However, API endpoints remain useful when:
- mobile apps need the same API
- third parties consume the backend
- multiple clients share services
- architecture requires service boundaries
Server Components do not make APIs obsolete.
Are Server Components More Secure?
They can improve architectural separation because server-only code does not need to be shipped to the browser.
For example, you can keep:
Database access code
Private service calls
Server-only packages
outside the client bundle.
However, Server Components do not automatically make an application secure.
You must still implement:
- authentication
- authorization
- input validation
- database security
- access control
- secure secret management
Never assume that server execution replaces normal security practices.
"use client" Does Not Mean the Entire App Must Be Client-Side
Consider:
"use client";
export default function Button() {
// ...
}
You only need the directive at an appropriate boundary.
You do not necessarily need:
"use client";
in every file that appears somewhere beneath the interactive UI.
The boundary allows the framework and bundler to determine which modules belong to the client-side graph. (React)
Therefore, carefully deciding where you place the boundary is important.
"use server" Does Not Create a Server Component
A common mistake is assuming:
"use server";
means:
This file is a Server Component.
That is incorrect.
React uses "use server" for Server Functions.
Meanwhile, Server Components are determined by the framework’s Server Component environment and module boundaries.
React’s documentation specifically notes that there is no equivalent "use server" directive for declaring Server Components. (React)
React Server Components in Next.js
Server Components are frequently discussed together with Next.js because the Next.js App Router provides an implementation of the architecture.
In the App Router, components are server-oriented by default unless a client boundary is introduced with:
"use client";
For example:
app/
├── page.jsx
├── layout.jsx
└── components/
└── Counter.jsx
page.jsx can remain server-side.
Meanwhile:
"use client";
can be added to Counter.jsx because the counter needs interaction.
Next.js documentation describes Server Components as the default model in its App Router. (Next.js)
Example Next.js Architecture
app/
│
├── page.jsx
│
├── products/
│ └── page.jsx
│
└── components/
├── ProductList.jsx
├── ProductCard.jsx
├── SearchBar.jsx
└── AddToCart.jsx
You could organize them as:
page.jsx
→ Server
ProductList.jsx
→ Server
ProductCard.jsx
→ Server
SearchBar.jsx
→ Client
AddToCart.jsx
→ Client
This creates a clear separation between server work and browser interaction.
Advantages of Server Components
Less Client-Side JavaScript
Server-only component implementation does not have to be downloaded as client code.
Direct Access to Server Resources
Components can work close to databases, files, and internal services where the runtime allows.
Natural Data Fetching
Async Server Components can retrieve data with await.
Keep Server Dependencies on the Server
Large processing libraries do not necessarily have to reach the browser.
Better Separation
Backend-oriented rendering stays server-side, while interaction stays client-side.
Streaming Support
Server Components can work with Suspense and streaming patterns.
Disadvantages of Server Components
Cannot Handle Browser Interaction Directly
Interactive features require Client Components.
Different Mental Model
Developers must understand server and client boundaries.
Framework Tooling Matters
RSC support depends on frameworks and bundlers that implement the architecture.
React notes that although Server Components themselves are stable in React 19, framework-level implementation APIs are still evolving. (React)
Serialization Boundaries
Values crossing from server to client must fit React’s supported serialization model.
Debugging Can Be Different
Developers must understand where each component is executing.
Advantages of Client Components
Full Interactivity
They support:
Clicks
Inputs
Forms
Animations
State
Effects
Browser APIs
You can access:
localStorage
window
navigator
document
Existing React Patterns
Most developers are already familiar with:
useState
useEffect
event handlers
Client Libraries
Many UI and browser-focused libraries naturally belong in Client Components.
Disadvantages of Client Components
More Browser JavaScript
Client component code and its client-side dependencies must be available to the browser.
Hydration/Initialization Cost
Interactive React code needs browser-side initialization.
Sensitive Server Code Cannot Be Included
Private backend credentials and server-only libraries must remain outside the client bundle.
Too Many Client Boundaries Can Reduce Benefits
If most of your application unnecessarily becomes client-side, you may lose some of the advantages of Server Components.
Common Beginner Mistakes
1. Making the Entire Page a Client Component
Bad approach:
"use client";
export default function ProductPage() {
// entire large page
}
even though only one button requires interaction.
A better structure might be:
ProductPage → Server
AddToCartButton → Client
2. Using useState in a Server Component
This will not work in a Server Component environment:
const [count, setCount] = useState(0);
Move interactive state into a Client Component instead.
3. Using Browser APIs on the Server
For example:
window.location
or:
localStorage.getItem("token")
requires a browser environment.
4. Confusing Server Components with SSR
Remember:
Server Components
≠
Server-Side Rendering
They can work together, but they describe different concepts.
5. Using "use server" Incorrectly
Do not add "use server" merely because you want a Server Component.
That directive is associated with Server Functions, not general Server Component declaration. (React)
6. Sending Sensitive Data to Client Components
A value is no longer private merely because it originally came from a Server Component.
Once you pass it to the client, treat it as client-visible data.
Server Components vs Client Components: Decision Guide
Use a Server Component when you need:
Database data
Server-side fetching
Server-only libraries
Non-interactive UI
Content rendering
Private backend operations
Use a Client Component when you need:
useState
useEffect
onClick
onChange
Browser APIs
Interactive UI
Client-side stores
Use both when your page contains server data and interaction.
That is often the ideal architecture.
Practical Example: Blog Website
Consider a blog post page.
You may need:
Article
Author information
Related posts
Like button
Comment form
Share menu
A sensible architecture is:
BlogPage — Server
│
├── Article — Server
├── Author — Server
├── RelatedPosts — Server
├── LikeButton — Client
├── CommentForm — Client
└── ShareMenu — Client
Most of the page requires no browser-side React state.
Therefore, only the interactive sections need to become Client Components.
Practical Example: E-Commerce Website
Consider:
Product data
Reviews
Price
Add to cart
Image gallery
Quantity selector
Possible architecture:
ProductPage — Server
├── ProductDetails — Server
├── Price — Server
├── Reviews — Server
├── ImageGallery — Client
├── QuantitySelector — Client
└── AddToCart — Client
This pattern keeps the client boundary focused.
Practical Example: Dashboard
A dashboard may be more interactive.
For example:
Dashboard — Server
├── UserInfo — Server
├── RecentOrders — Server
├── Statistics — Server/Client depending on chart
├── Filters — Client
├── DatePicker — Client
└── InteractiveChart — Client
Therefore, the server/client split does not need to happen only at page level.
You can choose boundaries throughout the component tree.
Server Components vs Client Components Learning Roadmap
If you are learning this architecture, follow this order.
Step 1: Learn React Fundamentals
Understand:
Components
Props
JSX
State
Hooks
Events
Step 2: Understand Client-Side Rendering
Learn how traditional React applications run in the browser.
Step 3: Understand Server-Side Rendering
Learn what HTML rendering on the server means.
Step 4: Learn Server Components
Understand:
Server execution
Async components
Server data fetching
Server-only dependencies
Step 5: Learn Client Components
Practice:
"use client";
and understand what creates a client boundary.
Step 6: Learn Composition
Build Server Components that contain smaller Client Components.
Step 7: Learn Suspense
Understand asynchronous rendering and loading boundaries.
Step 8: Learn Server Functions
After Server Components are clear, study Server Functions separately.
Step 9: Build a Real Project
Create a:
Blog
Dashboard
E-commerce site
Documentation website
using both component types.
Frequently Asked Questions
What is a Server Component in React?
A Server Component is a React component that renders in a server-side or build-time environment and does not require its component implementation to be shipped as client JavaScript.
What is a Client Component?
A Client Component is part of a client boundary and can use interactive React features such as state, effects, event handlers, and browser APIs.
Do Server Components use "use server"?
No.
There is no "use server" directive for declaring Server Components. "use server" is used for Server Functions. (React)
Do Client Components require "use client"?
You use "use client" at the module boundary that should become part of the client-side component graph.
Can Server Components use useState?
No.
Interactive state must live inside a Client Component.
Can Server Components use useEffect?
No.
Effects such as useEffect are client-side behavior.
Can Server Components use async/await?
Yes.
Async Server Components can await promises during rendering. (React)
Can Client Components fetch data?
Yes.
Client Components can fetch data through approaches such as browser fetch, TanStack Query, or other client-side tools.
Can Server Components access a database?
They can access server resources when the framework and runtime allow it. This is one of their major architectural benefits.
Are Client Components rendered only in the browser?
Not necessarily. In frameworks, Client Components can participate in server/prerendered initial output, but their JavaScript must also be available on the client for interaction.
Are Server Components the same as SSR?
No.
Server Components and SSR are different concepts, although frameworks may use them together.
Which is better: Server Components or Client Components?
Neither is universally better.
Server Components are ideal for server-side data and non-interactive UI. Client Components are required for browser interaction.
Can I use both in the same application?
Yes.
In fact, combining them is usually the intended architecture.
Conclusion
Server Components and Client Components solve different problems in modern React applications.
The easiest way to remember the difference is:
Server Components
→ Data, server resources and non-interactive UI
Client Components
→ State, events and browser interaction
A Server Component might:
Fetch products
Read database data
Render an article
Load a user profile
Process server-side content
Meanwhile, a Client Component might:
Open a modal
Toggle a menu
Handle a form
Update a counter
Use localStorage
Manage interactive state
Instead of making an entire application either server-side or client-side, modern React allows developers to define a server-client boundary.
A well-designed component tree might look like:
Page — Server
│
├── Header — Server
├── ProductDetails — Server
├── Reviews — Server
├── FavoriteButton — Client
├── CartButton — Client
└── SearchInput — Client
This approach lets the server perform work that belongs on the server while the browser receives JavaScript only for features that actually require interaction.
For beginners, the most useful rule is simple:
Start with server-oriented components where your framework supports them, and move a component behind
"use client"only when it needs client-side capabilities.
Once you understand this boundary, concepts such as React Server Components, Suspense, streaming, Server Functions, and modern Next.js architecture become much easier to understand. (React)




