Next.js & Server Components
Why frameworks exist, the App Router, Server vs Client Components, Server Functions and rendering strategies.
Everything so far has been a client-side React app: the server sends an almost empty HTML page and a JavaScript bundle, and the browser builds the UI. That's great for dashboards and tools, but it has trade-offs — slower first loads, weaker SEO, and API layers between your UI and your data. Next.js is the most popular React framework, and it solves these with server rendering, file-based routing and React Server Components. This final lesson gives you a working mental model and the essential APIs (Next.js 16, App Router).
Creating a project#
Accept the recommended defaults (TypeScript, Tailwind CSS and the App Router; Turbopack is the default bundler). Open http://localhost:3000.
File-based routing#
In the App Router, folders inside app/ define URLs, and a page.tsx makes a route public:
The root layout renders the <html> and <body>:
Layouts persist across navigations (their state isn't lost), and next/link gives client-side navigation with automatic prefetching.
Server Components: fetch data right in the component#
In the App Router, components are Server Components by default. They run only on the server (at build time or per request), so they can be async, read files, query databases and use secret keys — and none of their code is sent to the browser:
No useEffect, no loading state, no API route. The browser receives ready-made HTML, which is fast to display and easy for search engines to index. You could replace fetch with a direct database query (await db.post.findMany()), because this code never reaches the client.
Dynamic routes and params#
Folder names in brackets become params. In Next.js 16, params is a Promise you await:
generateMetadata sets the page <title> per post. Search params work the same way, via a searchParams promise prop.
Client Components: interactivity#
Server Components can't use state, effects, event handlers or browser APIs — they never run in the browser. For interactive parts, add "use client" at the top of the file:
Then use it from a Server Component like any component:
Client Components are still pre-rendered to HTML on the server, then hydrated in the browser so they become interactive. "use client" marks a boundary: that file and everything it imports become part of the client bundle.
Choosing Server vs Client#
The best practice is to keep pages and layouts as Server Components and push "use client" down to small, interactive leaves (buttons, forms, menus).
Composition rules
- Server Components can import and render Client Components.
- Client Components can't import Server Components — but they can receive them as
childrenor other props:
- Props passed from Server to Client Components must be serialisable (strings, numbers, plain objects, arrays, Dates, Promises) — not functions or class instances, except Server Functions.
Server Functions: mutations with "use server"#
A Server Function is an async function that runs on the server but can be called from the client — most often as a form action. Mark it with "use server":
This form even works before JavaScript loads (progressive enhancement). Everything from the React 19 features lesson applies: use useActionState for validation errors, useFormStatus for pending buttons and useOptimistic for instant feedback.
Tip: treat every Server Function like a public API endpoint — anyone can call it. Always validate input (e.g. with Zod) and check that the user is authenticated and authorised.
Loading and error UI#
You can also wrap slow parts of a page in your own <Suspense> boundaries so the rest streams to the browser immediately.
Rendering and caching in brief#
- Static pages are rendered at build time and served from a CDN — ideal for blogs and docs. Use
generateStaticParamsto pre-render dynamic routes. - Dynamic pages render per request, e.g. when they read cookies or headers.
- In Next.js 16,
fetchisn't cached by default. With Cache Components enabled (cacheComponents: trueinnext.config.ts), you opt in to caching explicitly with the"use cache"directive andcacheLife, and mix static and dynamic parts on the same page. next/imageoptimises images andnext/fontself-hosts fonts.
Deploying Next.js#
Unlike a Vite SPA, a Next.js app with server features needs a server runtime. Vercel (made by the Next.js team) supports everything out of the box; Netlify, Firebase App Hosting, Cloudflare and any Node.js host (npm run build && npm start, or Docker) work too. If you don't need server features, output: "export" produces a static site.
Next.js or Vite?#
- Vite + React Router: dashboards, internal tools, apps behind a login where SEO doesn't matter, or when you already have a separate backend.
- Next.js (or React Router's framework mode): public, content-heavy or SEO-sensitive sites, and full-stack apps that want UI and server code in one project.
Common mistakes#
- Adding
"use client"to every file "to make errors go away" — you lose the benefits of Server Components. - Using
useStateoronClickin a Server Component (Next.js shows an error that tells you to add"use client"). - Importing server-only code (database clients, secrets) into a Client Component. The
server-onlypackage makes this a build error. - Forgetting to
await paramsin Next.js 16. - Passing functions as props from Server to Client Components.
- Not validating input or checking auth in Server Functions.
What's next#
🎉 Congratulations — you've completed the React course! You've gone from your first component to Server Components. Keep building: pick a project (a habit tracker, a portfolio, a course-progress dashboard), ship it, and revisit lessons as you need them. The official docs at react.dev and nextjs.org are excellent next stops.
Check your understanding
Quick quiz
1.In the Next.js App Router, components are ____ by default.
2.Which component must be a Client Component?
3.What does the
"use server"directive mark?
Finished reading?
Mark this lesson complete to track your progress.