Skip to main content
Chapter 3 Data Fetching and Server Components

React Server Components Explained

22 min read Lesson 9 / 28

Server Components: The Paradigm Shift

React Server Components (RSC) are components that render exclusively on the server. They never run in the browser, which means they can directly access databases, file systems, and environment secrets — without exposing them to the client.

Server vs Client Components

// Server Component (default in app/ directory)
// - Runs only on the server
// - Can use async/await at the top level
// - Can access databases, env variables, file system
// - Cannot use useState, useEffect, browser APIs, event handlers
// - Zero JavaScript shipped to the browser

async function PostList() {
    const posts = await db.post.findMany({ where: { published: true } });

    return (
        <ul>
            {posts.map(post => (
                <li key={post.id}>{post.title}</li>
            ))}
        </ul>
    );
}
// Client Component — add 'use client' directive
// - Runs in the browser (also pre-rendered on server)
// - Can use useState, useEffect, event handlers, browser APIs
// - Cannot use server-only features

'use client';

import { useState } from 'react';

function LikeButton({ postId }: { postId: string }) {
    const [liked, setLiked] = useState(false);

    return (
        <button onClick={() => setLiked(!liked)}>
            {liked ? 'Unlike' : 'Like'}
        </button>
    );
}

The Composition Model

You can nest Client Components inside Server Components and pass Server-rendered data as props:

// app/blog/[slug]/page.tsx — Server Component
async function PostPage({ params }: { params: Promise<{ slug: string }> }) {
    const { slug } = await params;
    const post = await db.post.findUnique({ where: { slug } });

    return (
        <article>
            <h1>{post.title}</h1>
            <p>{post.content}</p>
            {/* Client Component receives serializable data from server */}
            <LikeButton postId={post.id} initialLikes={post.likesCount} />
            <CommentSection comments={post.comments} />
        </article>
    );
}

What Cannot Be Passed from Server to Client

Only serializable values can cross the server/client boundary:

// These CAN be passed as props to Client Components
// strings, numbers, booleans, arrays, plain objects, Date, null

// These CANNOT be passed
// Functions, class instances, Promises (unless using the use() hook)
// React Server Component elements — pass JSX as children instead

Server Components reduce the JavaScript bundle size dramatically. A large data-fetching component that used to ship as client code now runs entirely on the server, sending only HTML.