Skip to content
Next.js Fundamentals

Lesson 3 of 6 · 25 min

x
3/6

Lesson position in the course — not completion. Use Mark Complete to track finished lessons (saved in this browser).

React Server Components vs. Client Components

Next.js App Router components are React Server Components (RSC) by default. RSCs can execute direct database queries, access secure environment variables, and stream rendered chunks to the client using React Suspense. Because RSC code stays on the server, large npm libraries used inside them add 0 bytes to the client JavaScript bundle.

When a component requires interactivity — browser event listeners (onClick), React state hooks (useState), or browser APIs (window, localStorage) — you mark it as a Client Component by placing the 'use client' directive at the very top of the file. A best practice is to push 'use client' directives down the component tree, keeping parent containers as Server Components.

Before
Monolithic Client Component ('use client' at top level)
1'use client'; // ❌ Makes entire tree, DB logic, and libraries ship to client2import { useState } from 'react';3import HeavyLibrary from 'heavy-library';4 5export default function Dashboard({ initialData }) {6  const [filter, setFilter] = useState('');7  return (8    <div>9      <input value={filter} onChange={e => setFilter(e.target.value)} />10      <HeavyLibrary data={initialData} filter={filter} />11    </div>12  );13}
After
Decoupled Server Parent + Isolated Interactive Client Leaf
1// app/dashboard/page.tsx (Server Component - 0 client JS for heavy data)2import FilterableWidget from './filterable-widget';3import { getDashboardData } from '@/lib/db';4 5export default async function DashboardPage() {6  const data = await getDashboardData();7  return <FilterableWidget initialData={data} />;8}9 10// app/dashboard/filterable-widget.tsx11'use client'; // ✅ Only interactive control ships JS12import { useState } from 'react';13 14export function FilterableWidget({ initialData }) {15  const [filter, setFilter] = useState('');16  return <input value={filter} onChange={e => setFilter(e.target.value)} />;17}

Exercise

Refactor an interactive form card into a Server Component container with a separate Client Component toggle button for handling user clicks.

Check your understanding

  • Can a Server Component import a Client Component?Show answer

    Answer

    Yes — Server Components can render Client Components as children and pass serializable props to them.
  • What happens if you try to use useState inside a component without 'use client'?Show answer

    Answer

    Next.js compilation fails with a build error stating hooks can only be used in Client Components.
Previous

Progress is saved in this browser.

Next Lesson