Server Components vs Client Components

In plain React (ReactNotes / Vite), every component runs in the browser. In Next.js, every component is a Server Component BY DEFAULT โ€” it renders once on the server and ships to the browser as plain HTML, with zero JavaScript for that component included in the bundle.

Explain it like I'm 5

A Server Component is like a chef who cooks the meal in the kitchen (the server) and sends you the finished plate (HTML) โ€” you never see the recipe or the oven. A Client Component (anything with 'use client' at the top) is more like a meal-kit box: the ingredients and instructions ship to your kitchen (the browser) so YOU can interact with it โ€” stir it, change it, react to clicks.

1. This whole page is a Server Component

No 'use client' directive at the top, so this component (and the timestamp below) executed on the server. It can be an async function directly โ€” no useEffect needed to fetch data.
// app/server-components/page.tsx  (no "use client")
export default async function ServerComponentsPage() {
  const serverRenderedAt = new Date().toISOString()
  return <p>Rendered on the server at: {serverRenderedAt}</p>
}

Live result

Rendered on the server at: 2026-07-30T09:51:25.081Z

Refresh the page โ€” this timestamp updates every time, because this route re-renders on the server per request (see the SSR demo for more on that).

2. Interactivity requires 'use client'

useState, onClick, useEffect โ€” anything that needs to run in the browser after the page loads โ€” only works in a Client Component. Server Components can't hold state or attach event handlers.
// app/components/Counter.tsx
'use client'
import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0)
  return (
    <button onClick={() => setCount((c) => c + 1)}>{count}</button>
  )
}

Live result

0

3. Why default-to-server matters

Server Components never ship their code to the browser โ€” smaller JS bundles, faster page loads โ€” and they can safely touch secrets (API keys, database calls) directly, since that code never leaves the server.
// Fine in a Server Component โ€” this never reaches the browser bundle:
import { db } from '@/lib/database'
export default async function Orders() {
  const orders = await db.query('select * from orders')
  return <OrdersTable orders={orders} />
}

// NOT fine in a Client Component โ€” db would be bundled and its
// credentials/queries exposed to anyone reading the page's JS.