NextjsServer vs Client Components

Server vs Client Components

With both component types available, the natural question is: which one should this particular component be? The short answer is default to Server, opt into Client only when you need to — but a side-by-side comparison makes the reasoning concrete.

Server Component

Client Component

Where it renders

Server only (build time or request time)

Server (initial HTML) and browser (hydration + updates)

Can use hooks / state

No — no useState, useReducer

Yes

Can use event handlers

No — no onClick, onChange, etc.

Yes

Can access backend resources directly

Yes — databases, filesystem, secrets, internal services

No — must go through an API route or a Server Action

Ships JavaScript to the browser

No, for its own code

Yes — its code and dependencies are bundled and sent

Ideal for

Data fetching, layout, static content, anything non-interactive

Forms, toggles, counters, anything needing browser state or APIs

The general guidance
Tip
Default every new component to a Server Component. Only add 'use client' to the specific components that genuinely need interactivity, hooks, or browser APIs — and when you do, push that boundary as far down the component tree as possible, onto small "leaf" components, instead of marking an entire page or layout as a Client Component.
The reason to push the boundary down rather than up: marking a whole page as a Client Component makes everything inside it part of the client bundle by default (more on why in the composition patterns and "use client" directive pages), even the 90% of that page that's just static text and layout. Isolating the interactive part into its own small file keeps the rest of the page as cheap, JavaScript-free Server Components.
Worked example — one small Client Component, not a whole client page

Consider a product page: a title, a description, pricing info fetched from a database, and a "wishlist" heart button that toggles on click. Only the button needs interactivity.

components/WishlistButton.tsx — the one interactive leaf

TSX
'use client'

import { useState } from 'react'

export default function WishlistButton({ productId }: { productId: string }) {
  const [saved, setSaved] = useState(false)

  return (
    <button onClick={() => setSaved((prev) => !prev)}>
      {saved ? '♥ Saved' : '♡ Save for later'}
    </button>
  )
}

app/products/[id]/page.tsx — everything else stays a Server Component

TSX
import { db } from '@/lib/db'
import WishlistButton from '@/components/WishlistButton'

export default async function ProductPage({
  params,
}: {
  params: { id: string }
}) {
  // Runs on the server: direct DB access, no client-side fetch needed.
  const product = await db.product.findUnique({ where: { id: params.id } })

  return (
    <article>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <p>${product.price}</p>

      {/* Only this one component ships JS to the browser. */}
      <WishlistButton productId={product.id} />
    </article>
  )
}
The page itself never has a 'use client' directive. It fetches data directly from the database and renders static markup for the title, description, and price — none of that requires a single byte of client-side JavaScript. Only WishlistButton hydrates in the browser, and it's a tiny fraction of the page's total code.
  • Default to Server Components; they are cheaper (no JS shipped) and can access backend resources directly.

  • Add 'use client' only to components that specifically need hooks, event handlers, or browser APIs.

  • Push the client boundary down to small, focused leaf components rather than marking whole pages/layouts as client.

  • A Server Component page can freely import and render Client Components — this is the standard, recommended composition.