After this lesson, you will be able to: Distinguish Server Components from Client Components in Next.js, decide which to use for any new component, fetch data on the server without writing an API call, and add the `'use client'` boundary correctly.
Next.js's App Router introduced React Server Components — components that run ONLY on the server, fetch data directly, and send their rendered HTML to the browser without shipping their JavaScript. This is the single biggest mental shift from older React. Understanding it is the difference between writing fast, secure apps and dragging unnecessary JavaScript across every page. This lesson takes you from confused to comfortable in 50 minutes.
In the App Router, every component is a Server Component by default. They run on the server (during the request or at build time), fetch data, and send already-rendered HTML to the browser. No JavaScript for that component is shipped to the client. Client Components opt in with `'use client'` at the top of the file. They ship JavaScript to the browser, run there, and can use state, effects, and event handlers. Default = server. Opt in = client. Most components stay server; you add `'use client'` only when you need interactivity.
No `useEffect`, no loading state, no API endpoint. You `async`-fetch inside the component. The HTML returned to the browser already has the data baked in.
// app/users/page.tsx — Server Component by defaultexport default async function UsersPage() {const response = await fetch("https://jsonplaceholder.typicode.com/users", {// Next.js extends fetch with caching optionsnext: { revalidate: 60 }, // re-fetch at most every 60 seconds});const users: { id: number; name: string; email: string }[] =await response.json();return (<ul className="divide-y">{users.map((u) => (<li key={u.id} className="py-3"><p className="font-semibold">{u.name}</p><p className="text-sm text-slate-600">{u.email}</p></li>))}</ul>);}
Anything interactive — useState, useEffect, onClick handlers, browser APIs — needs `'use client'`. The directive must be the first non-comment line of the file.
"use client";import { useState } from "react";export function LikeButton({ initial = 0 }: { initial?: number }) {const [likes, setLikes] = useState(initial);return (<buttononClick={() => setLikes((n) => n + 1)}className="rounded bg-pink-600 px-3 py-1 text-white">♥ {likes}</button>);}
`'use client'` doesn't mean 'this one component is a client component.' It means 'this file AND every component it imports become client components.' The practical pattern: keep the boundary as deep as possible. Have a Server Component page that fetches data, then import a small Client Component for the interactive island. That way most of the page ships zero JavaScript and only the interactive bit (the button, the form) is hydrated.
The page is a Server Component — it fetches the data on the server. Inside, it renders a small Client Component for the interactive piece. The user sees the list immediately (no loading state); the like button hydrates when its JS arrives.
// app/posts/page.tsx — Server Component (no 'use client')import { LikeButton } from "./like-button";async function fetchPosts() {const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=5");return response.json();}export default async function PostsPage() {const posts = await fetchPosts();return (<ul className="space-y-4">{posts.map((post: { id: number; title: string }) => (<li key={post.id} className="border rounded p-4"><h2 className="font-semibold">{post.title}</h2><LikeButton /> {/* hydrates on the client */}</li>))}</ul>);}// app/posts/like-button.tsx — Client Component"use client";import { useState } from "react";export function LikeButton() {const [n, setN] = useState(0);return <button onClick={() => setN(n + 1)}>♥ {n}</button>;}
**Use a Server Component when:** the component just displays data; it needs database/file/secret access; it doesn't need state, effects, or browser APIs; you want to ship less JavaScript. (This is most components.) **Use a Client Component when:** it has interactivity (onClick, onChange, form input state); it uses hooks (useState, useEffect, useContext); it touches browser APIs (window, localStorage); it uses a third-party library that requires the browser (like a charting library).
Sign in and purchase access to unlock this lesson.