Take the same React app and put it in Next.js. Understand what Next adds: file-based routing, layouts, and server components.
package.json— depends onnextinstead of justviteapp/layout.jsx— wraps every page (nav bar lives here)app/globals.css— global stylesapp/page.jsx— the home route (/), a client component with the task trackerapp/TaskItem.jsx— child componentapp/about/page.jsx— the/aboutroute, a server component
cd 05-nextjs
npm install
npm run dev # starts on port 3000Next.js App Router uses folder structure for routing:
app/
├── layout.jsx # wraps all pages
├── page.jsx # / (home)
└── about/
└── page.jsx # /about
Add a folder with a page.jsx inside and you have a new route. No router config, no <Route path="..."> declarations.
Click between Home and About in the nav. Notice the page transitions instantly without a full reload — Next intercepts the navigation and only swaps the page content.
app/layout.jsx wraps every page. The nav is defined there, so it appears on every route. You can nest layouts too — app/about/layout.jsx would wrap only /about and its children.
By default in App Router, every component is a server component. It runs on the server, renders to HTML, and ships to the browser as plain HTML — no React JS runtime needed for that component.
Server components:
- ✅ Can fetch data directly (
const data = await fetch(...)) - ✅ Can use server-only secrets (API keys, DB connections)
- ✅ Ship zero JavaScript to the browser
- ❌ Cannot use
useState,useEffect, or any browser APIs - ❌ Cannot handle events (
onClicketc.)
To opt into a client component, add 'use client' at the top of the file. Then it behaves like the React component you wrote in Part 4.
Look at the two pages:
app/page.jsxhas'use client'at the top — it needs state, events, localStorageapp/about/page.jsxhas no directive — pure static content, runs on the server, ships as HTML
Open browser devtools → Network tab → reload the About page. The HTML arrives pre-rendered. Now reload the Home page — same, but plus the JS bundle needed for interactivity.
For real apps, you want server components by default (small bundles, fast loads, direct DB access) and client components only where you need interactivity (forms, animations, stateful widgets).
If you eventually wire a Next frontend to your codeminer.api Plumber backend, the natural pattern is:
- Server component fetches the codelist on the server (no API call from browser, no loading spinner)
- Client component handles the query builder UI (needs state)
| Part 4 (Vite + React) | Part 5 (Next.js) | |
|---|---|---|
| Routing | None — single page | File-based |
| Components | All client | Server by default, opt-in client |
| Data fetching | Browser-side (useEffect) |
Server-side (async server components) |
| Build output | Static SPA | SPA + SSR + API routes |
| Use when | Internal tools, simple apps | Public sites, content-heavy apps, anything with auth |
- Add a
/settingsroute. Createapp/settings/page.jsxas a server component with some static content. Add a link in the nav. - Change
app/about/page.jsx— add'use client'and auseStatebutton. It now works as a client component. - Remove
'use client'fromapp/page.jsxand reload. Read the error message — it tells you exactly why server components can't use state. - Look at the
<head>of the rendered HTML in devtools. Next has set the<title>from themetadataexport inlayout.jsx.
You've now built the same task tracker four different ways. The progression shows what each layer adds:
- HTML — structure
- CSS — presentation
- JS — interactivity (manually)
- React — interactivity (declaratively, with components)
- Next.js — React + routing + server rendering + a build pipeline
From here, the natural next steps depend on what you want to build. Some directions:
- Tailwind CSS for utility-first styling (much faster than handwritten CSS)
- TanStack Query for fetching data from APIs (relevant for a CodeMiner frontend)
- TypeScript for type safety (worth it as projects grow)
- Shadcn/ui for accessible, composable components
- Server Actions in Next.js for form submissions and mutations without writing API routes
→ Back to main README