If you follow the news in the React world, you've probably heard of Server Components, a technology that is causing heated discussions in the community. Some call it a revolution in front-end development, others call it an unnecessary complication.

What is Server Components?
Server Components are a new type of React components that are rendered exclusively on the server and never get into the browser. Sounds weird?
Let's look at a simple example:
// ServerComponent.js (server component)
async function BlogPost({ id }) {
// This code is executed ONLY on the server
const post = await db.posts.findById(id);
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}Please note: we directly access the database in the component! Previously, this was impossible — you had to create API endpoints, make fetch requests, process loading states... Now all this can be done directly in the component.
How do Server Components differ from regular ones?
Let's compare the three types of components to understand the difference:
1. Client Components
These are the usual React components that you know. They:
Running in browser
Can use hooks (useState, useEffect, etc.)
Can handle events (onClick, onChange)
Increase the size of the JavaScript bundle
'use client'; // We clearly indicate that this is a client component
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
}2. Server Components
A new type of components that:
Rendered ONLY on the server
Do not fall into the JavaScript bundle
Can work directly with databases and file system
CANNOT use state hooks or browser APIs
CANNOT process events
// By default, in Next.js 13+ all components are server-side
async function UserProfile({ userId }) {
// Direct access to the database is the server code!
const user = await db.users.findById(userId);
const posts = await db.posts.findByUser(userId);
return (
<div>
<h2>{user.name}</h2>
<p>{posts.length} постов</p>
</div>
);
}3. Server-Side Rendering (SSR)
Don't confuse Server Components with SSR! These are different things:
SSR — renders HTML on the server, but all JavaScript is still loaded into the browser for "hydration"
Server Components - do not send their JavaScript to the browser at all, only the finished result

Why is it necessary?
Problem #1: Bloated JavaScript Bundles
Imagine: you are displaying a list of products with markdown descriptions. Previously, you had to include a library for parsing markdown in the client bundle:
// The old approach - the library will get into the browser
import { marked } from 'marked'; // ~50kb
function Product({ description }) {
return <div dangerouslySetInnerHTML={{ __html: marked(description) }} />;
}With Server Components, the library remains on the server:
// New approach — the library does NOT get into the browser
import { marked } from 'marked';
async function Product({ productId }) {
const product = await db.products.findById(productId);
const html = marked(product.description);
return <div dangerouslySetInnerHTML={{ __html: html }} />;
}Result: the browser receives the finished HTML without the extra 50kb of JavaScript!
Problem #2: Waterfall of requests
A classic problem with React apps:
// Bad: a waterfall of requests
function Dashboard() {
const { user } = useUser(); // Request 1
if (!user) return <Loader />;
return <UserPosts userId={user.id} />; // Request 2 will start only after 1
}With Server Components, queries are executed in parallel on the server:
async function Dashboard() {
// Both requests will be executed in parallel!
const [user, posts] = await Promise.all([
db.users.getCurrent(),
db.posts.getRecent()
]);
return (
<div>
<UserInfo user={user} />
<PostsList posts={posts} />
</div>
);
}Problem #3: Safety
Server Components allow you to store secrets on the server:
// Safe - the API key will never get into the browser
async function WeatherWidget({ city }) {
const response = await fetch(
`https://api.weather.com/data?key=${process.env.WEATHER_API_KEY}&city=${city}`
);
const data = await response.json();
return <div>Температура: {data.temp}°C</div>;
}Case study: blog platform.
Let's look at a real application that combines both types of components:
// app/posts/[id]/page.js - server component
async function PostPage({ params }) {
// Data is being uploaded to the server
const post = await db.posts.findById(params.id);
const comments = await db.comments.findByPost(params.id);
return (
<article>
<h1>{post.title}</h1>
<PostContent content={post.content} />
{/* Клиентский компонент для интерактивности */}
<CommentForm postId={post.id} />
{/* Серверный компонент для отображения */}
<CommentsList comments={comments} />
</article>
);
}
// components/CommentForm.js - client component
'use client';
function CommentForm({ postId }) {
const [text, setText] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
await fetch('/api/comments', {
method: 'POST',
body: JSON.stringify({ postId, text })
});
setText('');
};
return (
<form onSubmit={handleSubmit}>
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
/>
<button type="submit">Отправить</button>
</form>
);
}Advantages of Server Components
✅ Less JavaScript in the browser
Only the interactive parts of the application are loaded into the browser. Everything else is on the server.
✅ Direct access to server resources
Database, file system, internal APIs — everything is directly accessible from the components.
✅ Best performance
Data is loaded close to the source (server → DB faster than browser → API → DB).
✅ Automatic code separation
You don't need to think about code splitting — server components don't automatically get into the bundle.
✅ Improved security
API keys, tokens, business process logic remain on the server.
Disadvantages and difficulties
❌ Steep learning curve
You need to understand which component is executed where. Beginners often get confused:
// ❌ Error: Server Component cannot use useState
async function UserProfile() {
const [isOpen, setIsOpen] = useState(false); // Oops!
// ...
}
// ✅ Correct: we take interactivity to the Client Component
async function UserProfile() {
const user = await db.users.getCurrent();
return <ProfileCard user={user} />; // ProfileCard can be client
}❌ Limited ecosystem
At the moment, full support is only available in Next.js 13+. Other frameworks are just beginning to implement this technology.
❌ Debugging difficulties
When part of the code is executed on the server and part in the browser, debugging becomes more difficult.
❌ More load on the server
Each request requires rendering on the server. You need to think about caching and scaling.
When to use Server Components?
Perfect for:
Pages with dynamic content — blogs, news feeds, product catalogs
Dashboards with a lot of data - analytics, reports, statistics
SEO-critical pages — all content is rendered on the server and is available to search engines
Applications with heavy dependencies — markdown, code highlighting, image processing
Not suitable for:
Highly interactive interfaces — editors, games, drawing apps
Offline apps — PWA that work without a server
Apps with real-time updates — chats, co-editing
How to start experimenting?
The easiest way to try Server Components is to create a new project on Next.js 13+:
npx create-next-app@latest my-app
cd my-app
npm run devIn Next.js 13+ with App Router, all components are server-side by default. To make the component client-side, just add 'use client' to the beginning of the file.
Practical advice.
1. Start with the server components
Make a component client-side only when it is really necessary (state, events, browser APIs).
2. Use "client boundary"
Take interactivity out into separate small components:
// Server component
async function ProductPage({ id }) {
const product = await db.products.findById(id);
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
{/* Только кнопка клиентская */}
<AddToCartButton productId={product.id} />
</div>
);
}3. Cache data
Next.js automatically caches fetch requests, but you can control this:
// Caching for 1 hour
const data = await fetch('https://api.example.com/data', {
next: { revalidate: 3600 }
});Is it worth studying? Definitely yes, especially if you work with Next.js or plan to do so. But remember: a good developer knows when to use a new technology and when to stick to proven solutions.
Server Components, hooks, performance, application architecture — this and much more can be learned in Codice! We analyze topics in detail, from the basics to advanced concepts, and consolidate knowledge with practical tasks.
💬 And if you need support or want to discuss the code — we already have more than 2000 like-minded people in active Telegram channel, where they help each other, share experiences and discuss current technologies!
Join Kodik — learn effectively, practice regularly, grow professionally! 🎯
Good luck mastering Server Components! Remember: the best way to understand technology is to try it in practice. Create a small project and experiment! 💻
