JavaScript & React

React Server Components: A Practical Deep Dive

React Server Components (RSC), introduced experimentally in 2020 and stabilised in Next.js 13’s App Router in 2023, are the most significant architectural change to React since Hooks. They shift rendering back toward the server without sacrificing the component model — and the mental model takes time to adjust to.

The Core Idea

In the App Router, every component is a Server Component by default. Server Components run only on the server — they can access databases, file systems, and environment variables directly. They never run in the browser, so they add zero JavaScript to the client bundle.

// app/posts/page.tsx — Server Component (default)
// This function runs on the server, never in the browser
async function PostsPage() {
    // Direct database access — no API route needed
    const posts = await db.query('SELECT * FROM posts ORDER BY created_at DESC');

    return (
        <ul>
            {posts.map(post => (
                <li key={post.id}><PostCard post={post} /></li>
            ))}
        </ul>
    );
}

Client Components: The Explicit Exception

When you need interactivity, browser APIs, or React state, add "use client" at the top of the file:

"use client";

import { useState } from 'react';

export function LikeButton({ initialLikes }: { initialLikes: number }) {
    const [likes, setLikes] = useState(initialLikes);
    return <button onClick={() => setLikes(l => l + 1)}>♥ {likes}</button>;
}

Composing Server and Client Components

Server Components can render Client Components. Client Components cannot render Server Components (because Client Components run in the browser where there is no server). The boundary flows one way: server → client.

Streaming with Suspense

Wrap slow server components in <Suspense> to stream their content progressively — the shell renders immediately and slow parts stream in as they resolve:

export default function Dashboard() {
    return (
        <>
            <h1>Dashboard</h1>
            <Suspense fallback={<Skeleton />}>
                <SlowAnalyticsWidget /> {/* streams in when ready */}
            </Suspense>
        </>
    );
}

Server Actions

Server Actions (stable in Next.js 14) allow form submissions and mutations to call server functions directly, without writing API route boilerplate:

"use server";

export async function createPost(formData: FormData) {
    const title = formData.get('title') as string;
    await db.insert({ title, createdAt: new Date() });
    revalidatePath('/posts');
}

When to Use RSC vs Traditional API Routes

  • RSC for reads (fetching data for rendering)
  • Server Actions for mutations (forms, button clicks that change data)
  • API routes for public APIs consumed by mobile apps or third parties

React Server Components require a new mental model, but the payoff — smaller client bundles, simpler data fetching, and better performance by default — makes them the right architecture for most Next.js applications in 2023.

Share this post:
Copied!

Leave a Comment

Your email will not be published.

READY TO BUILD?

Let's Build Something
Amazing Together

Tell us about your project. We'll have a proposal in your inbox within 24 hours.

Free Consultation
NDA Available
Fixed-price Options
Dedicated PM