← Back to articles

Server Components vs Client Components Explained (2026)

React Server Components (RSC) changed how we build React apps. Components run on the server by default. Client Components run in the browser when you need interactivity. Here's how they work and when to use each.

The Simple Rule

Server Component (default): Runs on the server. No JavaScript sent to the browser. Can directly access databases, APIs, and the file system.

Client Component ('use client'): Runs in the browser. Has state, effects, event handlers, and browser APIs.

Server Component → Static HTML (fast, no JS)
Client Component → Interactive UI (JS required)

How They Work

Server Component (Default in Next.js App Router)

// app/page.tsx — Server Component by default
import { db } from '@/lib/db'

export default async function HomePage() {
  // This runs on the server — direct database access!
  const posts = await db.select().from(postsTable).limit(10)

  return (
    <div>
      <h1>Latest Posts</h1>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  )
}

What happens: Server fetches data, renders HTML, sends it to the browser. Zero JavaScript for this component. Instant load.

Client Component

'use client' // ← This makes it a Client Component

import { useState } from 'react'

export function LikeButton({ postId }: { postId: string }) {
  const [liked, setLiked] = useState(false)
  const [count, setCount] = useState(0)

  const handleLike = async () => {
    setLiked(!liked)
    setCount(prev => liked ? prev - 1 : prev + 1)
    await fetch(`/api/posts/${postId}/like`, { method: 'POST' })
  }

  return (
    <button onClick={handleLike}>
      {liked ? '❤️' : '🤍'} {count}
    </button>
  )
}

What happens: JavaScript is sent to the browser. Component hydrates and becomes interactive.

When to Use Each

Server Components ✅

  • Fetching data (database queries, API calls)
  • Rendering static content (blog posts, product pages)
  • Accessing server-only resources (environment variables, file system)
  • Large dependencies (markdown parsers, syntax highlighters — not sent to client)
  • SEO-critical content
  • Layout and page structure

Client Components ✅

  • User interaction (clicks, form inputs, toggles)
  • State management (useState, useReducer)
  • Effects (useEffect, subscriptions)
  • Browser APIs (window, localStorage, navigator)
  • Event listeners (onClick, onChange, onSubmit)
  • Third-party client libraries (charts, maps, rich text editors)

The Pattern: Server Parent, Client Children

// Server Component (parent)
export default async function ProductPage({ params }) {
  const product = await db.query.products.findFirst({
    where: eq(products.id, params.id),
  })

  return (
    <div>
      {/* Static content — Server Component */}
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <img src={product.image} alt={product.name} />

      {/* Interactive parts — Client Components */}
      <AddToCartButton productId={product.id} price={product.price} />
      <ReviewSection productId={product.id} />
    </div>
  )
}

The page structure and data fetching happen on the server. Interactive widgets are Client Components.

Common Mistakes

❌ Making Everything a Client Component

'use client' // Don't add this to every file!

export default function BlogPost({ post }) {
  return <article><h1>{post.title}</h1><p>{post.content}</p></article>
}

This component has no interactivity. It should be a Server Component (default).

❌ Fetching Data in Client Components

'use client'
export default function Posts() {
  const [posts, setPosts] = useState([])
  useEffect(() => {
    fetch('/api/posts').then(r => r.json()).then(setPosts) // ❌ Slow
  }, [])
}

Fetch data in Server Components instead. No loading state, no waterfall, no client-side fetch.

❌ Passing Functions as Props to Client Components

// Server Component
export default function Page() {
  const handleClick = () => console.log('clicked') // ❌ Can't serialize functions
  return <ClientButton onClick={handleClick} />
}

Functions can't be passed from Server to Client Components. Use Server Actions instead.

Server Actions (Mutations)

// Server Component with Server Action
export default function CreatePostForm() {
  async function createPost(formData: FormData) {
    'use server'
    const title = formData.get('title') as string
    await db.insert(posts).values({ title })
    revalidatePath('/posts')
  }

  return (
    <form action={createPost}>
      <input name="title" placeholder="Post title" />
      <button type="submit">Create</button>
    </form>
  )
}

No API route needed. The form calls a server function directly.

Performance Impact

Server ComponentClient Component
JavaScript sent0 bytesComponent code + React
Time to InteractiveInstant (HTML)After hydration (~200ms)
Data fetchingServer-side (fast)Client-side (waterfall)
SEO✅ Full HTML⚠️ Depends on rendering

Rule of thumb: Every Client Component adds JavaScript to your bundle. Minimize them.

FAQ

Can Server Components use hooks?

No. useState, useEffect, useContext — all require 'use client'. Server Components can't have state or effects.

Can I fetch data in Client Components?

Yes, but prefer Server Components. Use Client Components for data fetching only when you need real-time updates or user-triggered fetches.

Do Server Components work outside Next.js?

Remix supports them experimentally. React's official RSC support requires a framework. Next.js has the most mature implementation.

What about React Context?

Context providers must be Client Components. Wrap them around Server Components that need the context.

Bottom Line

Default to Server Components. Only add 'use client' when you need interactivity (state, effects, event handlers). The pattern: Server Components for data and layout, Client Components for interactive widgets. This gives you the fastest possible pages with interactivity where it matters.

Get AI tool guides in your inbox

Weekly deep-dives on the best AI coding tools, automation platforms, and productivity software.