🤔 What Are React Server Components (RSCs)?
For years, React components have run almost exclusively in the browser (the "client"). When a user visits a page, the JavaScript for all the components is downloaded and "hydrated" to make the page interactive. This can lead to large bundle sizes and slower initial load times.
React Server Components are a new type of component that runs exclusively on the server. They are never shipped to the client, meaning their code doesn't add to your JavaScript bundle size.
The key benefits are:
- Zero Bundle Size: Server Components have no impact on the client-side JavaScript bundle. This means faster initial page loads.
- Direct Backend Access: They can directly access server-side resources like databases, file systems, or internal APIs without needing to make a separate API call from the client.
- Automatic Code Splitting: They act as natural code-splitting points. Any component imported by a Server Component will only be bundled if it's also used by a Client Component.
Server vs. Client Components
In this new paradigm, every component is a Server Component by default. To create a component that runs in the browser (the kind you're used to), you must explicitly opt-in by placing the "use client" directive at the top of the file.
FeatureServer Components (Default)Client Components ("use client")EnvironmentServer-onlyServer (for SSR) + ClientInteractivityNo (cannot use useState, useEffect, event listeners)Yes (can use all hooks and event listeners)Data FetchingYes, using async/awaitYes, typically inside useEffectJS BundleNot included in the client bundleIncluded in the client bundle
Export to Sheets
Think of it like this: use Server Components for fetching data and presenting non-interactive UI, and use Client Components for anything that requires user interaction or browser-specific APIs.
💻 Code Examples
Let's see this in action. Imagine we're building a blog.
A Data-Fetching Server Component
Here's a component that fetches a list of blog posts. Notice how we can use async/await directly in the component. This file does not need "use client".
JavaScript
// app/components/PostList.js
// This function simulates fetching data from a database
async function getPosts() {
  const res = await fetch('https://api.example.com/posts');
  if (!res.ok) {
    throw new Error('Failed to fetch posts');
  }
  return res.json();
}
// This is a Server Component by default!
export default async function PostList() {
  const posts = await getPosts();
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
This component runs on the server, fetches the data, and sends the resulting HTML to the browser. Zero JavaScript for this component is sent to the client.
An Interactive Client Component
Now, let's create a "Like" button. Since it needs to respond to user clicks and manage state, it must be a Client Component.
JavaScript
// app/components/LikeButton.js
"use client"; // This directive marks it as a Client Component
import { useState } from 'react';
export default function LikeButton() {
  const [likes, setLikes] = useState(0);
  function handleClick() {
    setLikes(likes + 1);
  }
  return (
    <button onClick={handleClick}>
      👍 Like ({likes})
    </button>
  );
}
You can seamlessly use a Client Component inside a Server Component. React handles the integration.
JavaScript
// app/page.js
import PostList from './components/PostList';
import LikeButton from './components/LikeButton'; // A Client Component
// This page is a Server Component
export default function HomePage() {
  return (
    <main>
      <h1>My Awesome Blog</h1>
      <PostList />
      <hr />
      <p>Enjoyed the content? Leave a like!</p>
      <LikeButton />
    </main>
  );
}