Server, client and data · Lesson 5 of 16
Server and Client Components
Which code runs where, "use client", and the boundary between them.
In the App Router every component is a Server Component by default: it runs only on the server, and the browser receives the resulting HTML without its JavaScript. You can query the database directly, use secret keys and heavy libraries, and none of it reaches the user.
But Server Components have no interactivity: no useState, onClick or useEffect. For those, write "use client" at the top of a file, making that component (and everything it imports) a Client Component.
// app/courses/[slug]/page.tsx: a Server Component (the default)
import { db } from "@/lib/db" // server-only code, never sent to the browser
import { LikeButton } from "./like-button"
export default async function CoursePage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params
const course = await db.course.findBySlug(slug) // direct database access
return (
<article>
<h1>{course.title}</h1>
<p>{course.description}</p>
<LikeButton courseId={course.id} initialLikes={course.likes} />
</article>
)
}
// app/courses/[slug]/like-button.tsx: a Client Component
"use client"
import { useState } from "react"
export function LikeButton({ courseId, initialLikes }: { courseId: string; initialLikes: number }) {
const [likes, setLikes] = useState(initialLikes)
return <button onClick={() => setLikes(likes + 1)}>♥ {likes}</button>
}- CoursePage (server): reads the DB, sends HTML only
- <h1>, <p> (server): zero JavaScript
- "use client" boundary
- LikeButton (client): HTML + its JavaScript, hydrated in the browser
Only client components' JavaScript reaches the browser.
| Need | Server | Client |
|---|---|---|
fetch data from the database | ✅ | ❌ |
secret API keys | ✅ | ❌ |
useState / useEffect | ❌ | ✅ |
onClick, onChange | ❌ | ✅ |
window, localStorage | ❌ | ✅ |
less browser JavaScript | ✅ | ❌ |
Spot the bug
This file errors. Which line is the cause?
Exercise
This LikeButton is a client component: it takes initialLikes from the server, each press adds one, and it shows ♥ N. The checker presses twice, starting from 41.
The page should show: ♥ 43
function LikeButton({ initialLikes }) {
return <button>♥ {initialLikes}</button>
}
// Stands in for the Server Component that passes data down
function App() {
return <LikeButton initialLikes={41} />
}Learn more from
Played 0 of 2 games
Sign in to save your progress and earn XP.