Server Components in Next.js Explained Simply
API & Data

Server Components in Next.js Explained Simply

October 22, 2025
9 min read
3.3K views
Pradeep M

Pradeep M

Full-Stack Developer

# Server Components in Next.js Explained Simply

Introduction

"Wait, so components run on the server now? But React runs in the browser, right?"

If you've been confused by Server Components, you're not alone. When Next.js 13 introduced the App Router with React Server Components, many developers scratched their heads. How do components run on the server? What about useState? When do I use "use client"?

The shift from Next.js 12 to Next.js 13–15 represents a fundamental change in how we build React apps. The goal? Faster, more efficient web applications that deliver less JavaScript to users while maintaining the interactivity we love.

This guide will explain Server Components in simple terms, show you exactly when to use them, and help you understand how they work alongside traditional Client Components. No jargon, just clear explanations with practical examples.

Let's demystify Server Components once and for all.


What Are React Server Components (RSC)?

Here's the simplest definition:

Server Components are React components that run only on the server—never in the browser.

Think about it this way: traditionally, all React components get bundled into JavaScript, sent to the browser, and executed there. With Server Components, the component runs on the server, renders to a special format, and sends only the HTML result to the browser.

The Key Difference

Traditional React Component (Client Component):

  1. Server sends JavaScript bundle
  2. Browser downloads the bundle
  3. React executes and renders the component
  4. User sees the content

Server Component:

  1. Server runs the component
  2. Server sends rendered result (not JavaScript)
  3. User sees the content immediately
  4. No component JavaScript in the bundle

This means Server Components never increase your JavaScript bundle size. They don't exist in the client-side code at all.

Next.js Leads the Way

Next.js was the first major framework to fully adopt React Server Components. As of Next.js 13+, all components in the App Router are Server Components by default—unless you explicitly mark them as Client Components.

This is a huge shift from Next.js 12 and earlier, where everything was a Client Component by default.


Server Components vs Client Components

Let's break down the differences with a clear comparison:

FeatureServer ComponentClient Component
Runs OnServerBrowser
Can Use Hooks like 'useState'?❌ No✅ Yes
Can Fetch Data Directly?✅ Yes⚠️ Needs API
Increases Bundle Size?❌ No✅ Yes
Can Access Backend Resources?✅ Yes (DB, filesystem)❌ No
Can Use Browser APIs?❌ No✅ Yes (window, localStorage)
Ideal ForData fetching, static contentInteractive UI, forms

Mixing Both: The Power of Hybrid Apps

The magic happens when you combine both types. Use Server Components for the heavy lifting (data fetching, rendering static content) and Client Components for interactivity (buttons, forms, animations).

Next.js makes this seamless. You can nest Client Components inside Server Components, creating powerful hybrid applications that are both fast and interactive.


How Server Components Improve Performance

Server Components deliver multiple performance benefits:

1. Smaller JavaScript Bundles

Server Components don't ship JavaScript to the browser. If you have a large data-fetching component that renders a list, all that code stays on the server.

Before (Client Component):


Bundle size: 150KB (includes component + dependencies)

After (Server Component):


Bundle size: 0KB (component runs on server)

2. Automatic Data Fetching

Server Components can fetch data directly from databases or APIs without creating separate API routes:

typescript
// This runs on the server, not the browser
async function ProductList() {
const products = await db.products.findMany();
return 

    {products.map(p => 
  • {p.name}
  • )}
;
}

No need for:

  • Client-side fetch calls
  • Loading states
  • Error handling on the client
  • Extra API endpoints

3. Faster First Paint

Because Server Components render on the server, users see content faster. There's no waiting for JavaScript to download, parse, and execute before seeing the page.

4. Less Hydration

Hydration is the process where React "activates" server-rendered HTML in the browser. Server Components don't need hydration because they don't have client-side JavaScript. This reduces the work the browser needs to do.

Example: Before and After

Old Way (Client Component):

typescript
"use client";
import { useState, useEffect } from 'react';


export default function Page() { const [products, setProducts] = useState([]);

useEffect(() => { fetch('/api/products') .then(res => res.json()) .then(data => setProducts(data)); }, []);

return (

Shop

{products.map(p =>
{p.name}
)}
); }

New Way (Server Component):

typescript
// app/page.tsx
import ProductList from './ProductList';


export default function Page() { return (

Shop

); }

// ProductList.tsx (Server Component by default) async function ProductList() { const res = await fetch('https://api.example.com/products'); const products = await res.json();

return (

{products.map(p =>
{p.name}
)}
); }

The second version is simpler, faster, and requires zero client-side JavaScript for the data fetching logic.


When to Use Server vs Client Components

Understanding when to use each type is crucial for building efficient Next.js apps.

Use Server Components For:

Fetching data from databases or external APIs

typescript
async function BlogPosts() {
const posts = await db.post.findMany();
return ;
}

Rendering static content

typescript
function AboutPage() {
return (


About Us

We've been in business since 2020...


);
}

SEO-critical pages Server Components render on the server, making content immediately available to search engines.

Accessing backend resources

typescript
async function ServerLogs() {
const logs = await fs.readFile('/var/log/app.log', 'utf-8');
return 

{logs}
;
}

Use Client Components For:

Interactive elements requiring state

typescript
"use client";
import { useState } from 'react';


export default function LikeButton() { const [liked, setLiked] = useState(false);

return (
<button onClick={() => setLiked(!liked)}>
{liked ? "❤️ Liked" : "♡ Like"}

);
}

Forms and user inputs

typescript
"use client";
import { useState } from 'react';


export default function ContactForm() { const [email, setEmail] = useState('');

return (

<input value={email} onChange={(e) => setEmail(e.target.value)} />
); }

Browser-specific features

typescript
"use client";
import { useEffect } from 'react';


export default function ThemeToggle() { useEffect(() => { const theme = localStorage.getItem('theme'); document.body.className = theme; }, []);

return ;
}

Animations and interactive dashboards Anything using event listeners, timers, or browser APIs needs to be a Client Component.

The "use client" Directive

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

typescript
"use client";
import { useState } from 'react';


export default function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count};
}

Important: You only need this at the "boundary" where you transition from server to client. Child components automatically inherit the client behavior.

The Role of the App Directory in Next.js

The '/app' directory is where Next.js 13+ enables React Server Components by default.

Key Files in the App Directory

'page.tsx' - The main page component (Server Component by default) 'layout.tsx' - Wraps pages with shared UI (Server Component by default) 'loading.tsx' - Shows while the page loads (Server Component) 'error.tsx' - Handles errors (must be Client Component)

Example Folder Structure


app/
├── layout.tsx              (Server Component)
├── page.tsx                (Server Component)
├── loading.tsx             (Server Component)
├── dashboard/
│   ├── page.tsx            (Server Component)
│   ├── Chart.tsx           (Client Component with "use client")
│   └── Sidebar.tsx         (Server Component)
└── blog/
    ├── page.tsx            (Server Component)
    └── [slug]/
        └── page.tsx        (Server Component)

Default Behavior

In the App Router:

  • Everything is a Server Component unless you add '"use client"'
  • This is the opposite of the Pages Router (Next.js 12), where everything was a Client Component

This default makes sense: most components don't need interactivity. They just render content.


Data Fetching with Server Components

One of the most powerful features of Server Components is direct data fetching.

Direct API Calls

No need for API routes in many cases:

typescript
// app/posts/page.tsx
export default async function Posts() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await res.json();


return (

Blog Posts

    {posts.slice(0, 5).map((post) => (
  • {post.title}
  • ))}
); }

Direct Database Access

With Server Components, you can query your database directly:

typescript
// app/products/page.tsx
import { db } from '@/lib/db';


export default async function Products() { const products = await db.product.findMany({ where: { inStock: true }, orderBy: { createdAt: 'desc' }, });

return (

{products.map(product => ( ))}
); }

Why This Is Powerful

No API routes needed - Skip the middleman for many use cases

Data ready on first render - No loading spinners for initial data

Better SEO - Content is available immediately for search engines

Secure - Database credentials and secrets never reach the client

Faster - Fewer network roundtrips

Caching and Revalidation

Next.js automatically caches fetch requests. You can control this:

typescript
// Revalidate every 60 seconds
export const revalidate = 60;


export default async function Posts() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return ;
}

Common Misconceptions

Let's clear up some confusion:

❌ "Server Components replace APIs"

Not true. APIs are still important for:

  • Client-side data fetching
  • Third-party integrations
  • Mobile apps
  • Public data endpoints

Server Components simplify data fetching for web pages, but APIs remain valuable.

❌ "You can't use any hooks"

Partially true. You can't use hooks that require client-side reactivity (useState, useEffect, etc.), but you can use:

  • Context (for sharing data between Server Components)
  • Async/await (since Server Components are async)

❌ "Server Components are complex"

Actually simpler when structured properly. They remove the need for:

  • useState for loading/error states
  • useEffect for data fetching
  • API route creation
  • Client-side fetch logic

The code becomes more straightforward.

❌ "Everything should be a Server Component"

Not true. Use the right tool for the job:

  • Interactive UI → Client Component
  • Static content/data fetching → Server Component

Benefits at a Glance

Here's what you gain with Server Components:

🚀 Faster Page Loads Less JavaScript to download and execute

💾 Smaller JS Bundles Server Components add zero bytes to your bundle

Better SEO and TTFB Content renders server-side, improving Time to First Byte

🧩 Simpler Data Fetching No need for useEffect and loading states

🔒 More Secure Backend secrets never exposed to the client

🎯 Better Performance Less hydration and faster interactivity

Conclusion

React Server Components represent a fundamental shift in how we build modern web applications. They're not just a Next.js feature—they're a React innovation that Next.js pioneered.

The key insight is simple: not everything needs to run in the browser. By moving non-interactive code to the server, we create faster, lighter applications that still deliver the rich interactivity users expect.

The Mental Model

Think of your app in two layers:

  1. Server Components - The static shell that fetches data and renders structure
  2. Client Components - The interactive islands that respond to user actions

Master this separation, and you've unlocked Next.js superpowers.

Getting Started

If you're building a new Next.js 15 project:

  1. Start with Server Components by default
  2. Add '"use client"' only when you need interactivity
  3. Fetch data directly in Server Components
  4. Keep your bundle size small

The beauty of Server Components is that once you understand which parts belong on the server and which on the client, everything clicks into place.

Go experiment. Build something. Break the mental model of "React only runs in the browser." The future of web development is here, and it's faster than ever.

Happy coding! 🚀

Pradeep M

About Pradeep M

Full-stack developer passionate about building scalable web applications and sharing knowledge with the community.

Share this article

Related Articles

Next.js Animations: A Complete Guide
Development

Next.js Animations: A Complete Guide

Master animation techniques in Next.js with Framer Motion and CSS animations.

Improving SEO in React Applications
SEO

Improving SEO in React Applications

Best practices for optimizing your React apps for search engines.

Building Modern APIs with GraphQL
Backend

Building Modern APIs with GraphQL

Learn how GraphQL simplifies data fetching in modern applications.

10 minRead More
Server Components in Next.js Explained Simply | Trulyzer Blog