stackademic

The leading education platform for anyone with an interest in software development.

React Server Components

Render components on the server to cut bundle size and fetch data directly

Overview

React Server Components (RSC) run only on the server and never ship their JavaScript to the browser. They can fetch data directly, access server resources, and keep secrets out of the client bundle. Interactive pieces opt into the client with the 'use client' directive; server and client components compose in the same tree.

Syntax / Usage

Server components are async functions that await data directly—no useEffect, no loading spinner plumbing.

// app/posts/page.tsx — a Server Component by default
async function PostsPage() {
  const res = await fetch('https://api.example.com/posts', {
    next: { revalidate: 60 },
  })
  const posts: Post[] = await res.json()

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

export default PostsPage

Examples

Mark interactive components with 'use client'; only these ship JS and may use hooks or event handlers:

'use client'
import { useState } from 'react'

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

Compose them: a server component fetches data and passes serializable props to a client child:

async function Post({ id }: { id: string }) {
  const post = await getPost(id)
  return (
    <article>
      <h1>{post.title}</h1>
      <LikeButton initial={post.likes} />
    </article>
  )
}

Common Mistakes

  • Using hooks (useState, useEffect) or browser APIs in a server component—those need 'use client'
  • Passing non-serializable props (functions, class instances) from server to client components
  • Importing a server-only module into a client component and leaking secrets to the bundle
  • Assuming every component must be a client component; keep the default (server) where possible
  • Forgetting that 'use client' marks a boundary—everything imported below it becomes client code

See Also

react-suspense use-effect components