Transition from building standalone React client interfaces to architecting scalable, production-grade full-stack web applications. Master the App Router, file-system routing, root & nested layouts, client-side navigation with Link, and the foundational paradigm of Server Components vs. Client Components ("use client").
The Shift from a Frontend UI Library to a Complete Full-Stack Web Framework
In traditional React, you are working with a UI library. React only provides the component model (UI = fn(state)). When building a complete web application, you were forced to manually stitch together third-party routing libraries (React Router), build tools (Webpack/Vite), data fetching solutions, and SSR servers.
Next.js is the official React framework for full-stack web applications. It wraps React with an opinionated, high-performance architecture:
With Next.js, your code can run on the server to query databases or fetch data securely, and seamlessly hydrate interactive components in the user's browser without boilerplate.
Project Initialization, Development Server & App Router Directory Structure
create-next-appThe standard, official way to generate a new Next.js application is with the interactive CLI tool:
# 1. Generate new Next.js application npx create-next-app@latest my-learning-platform # Prompts: ✔ Would you like to use TypeScript? Yes ✔ Would you like to use ESLint? Yes ✔ Would you like to use Tailwind CSS? Yes / No ✔ Would you like your code inside a `src/` directory? Yes ✔ Would you like to use App Router? (Recommended) Yes ✔ Would you like to use `@/*` import alias? Yes # 2. Start the development server cd my-learning-platform npm run dev # -> Server running on http://localhost:3000
Folders Define Route Segments; page.tsx Defines Publicly Accessible UI
In the App Router, folders define URL route segments, and only the special file page.tsx makes a segment publicly addressable:
[id]When a route path depends on dynamic data (such as a course ID or slug), wrap the folder name in square brackets:
// Route: /courses/react-101 or /courses/42
// In Next.js 15, params is an asynchronous Promise that must be awaited:
export default async function CourseDetailPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
return (
<article>
<h1>Course: {id}</h1>
<p>Dynamic route segment resolved on the server.</p>
</article>
);
}Shared UI Hierarchies with layout.tsx and Instant SPA Navigation with Link
A layout is UI that is shared across multiple pages. When navigating between sibling routes, layouts preserve their component state, avoid unnecessary re-renders, and remain interactive:
Mandatory root file that defines <html> and <body>. Wraps every page in your application with global headers, footers, and font providers.
Applies only to routes inside /dashboard/*. Perfect for persistent student sidebars, breadcrumb headers, or tab bars without re-rendering the root layout.
<Link>Never use standard HTML <a href="..."> for internal links! Standard anchor tags trigger a full-page browser reload, wiping React state and re-fetching assets. The Next.js <Link> component performs seamless client-side soft navigation with automatic viewport prefetching:
import Link from 'next/link';
export function Navigation() {
return (
<nav>
{/* Prefetched automatically in background when visible in viewport */}
<Link href="/dashboard">Dashboard</Link>
<Link href="/courses">All Courses</Link>
</nav>
);
}Server by Default: When to Run on the Server vs When to Mark "use client"
In the App Router, every component is a Server Component by default. They execute exclusively on the server, emitting lightweight HTML/RSC payloads to the browser without shipping their JavaScript dependencies to the client.
useState or event listeners (onClick)."use client" at the top of the file.useState, useReducer.onClick, onChange, onSubmit.localStorage, geolocation.Main Practical Activity: Executable Multi-Route App Router Project with Simulated Browser
app/layout.tsx with global navapp/courses/page.tsxapp/courses/[id]/page.tsxapp/dashboard/layout.tsxBookmarkButton.tsxLinkFast client transitions, persistent layouts, and server-side data fetching.
Interactive Anti-Pattern Sandbox: 5 Frequent Pitfalls in Next.js Development
// app/courses/page.tsx
// ❌ BROKEN: Server Component trying to use client hooks
import { useState } from 'react';
export default function CoursesPage() {
const [query, setQuery] = useState(''); // Crashes build / runtime!
return <input value={query} onChange={e => setQuery(e.target.value)} />;
}// File Structure: app/ ├── layout.tsx ├── page.tsx └── about.tsx <-- ❌ BROKEN in App Router! Visiting http://localhost:3000/about returns 404 NOT FOUND!
pages/about.tsx worked. In the App Router, files directly under app/ (other than page.tsx or layout.tsx) are ignored as route endpoints.// app/layout.tsx
export default function Navbar() {
// ❌ BROKEN: Triggers a hard full-page browser refresh!
return <a href="/dashboard">Dashboard</a>;
}// app/courses/[id]/page.tsx (Next.js 15)
// ❌ BROKEN: Treating params as a synchronous object
export default function CoursePage({ params }: { params: { id: string } }) {
return <h2>Course: {params.id}</h2>;
}// app/layout.tsx
// ❌ BROKEN: Forgetting to output children
export default function RootLayout() {
return (
<html>
<body>
<header>Global Nav</header>
{/* Child page.tsx is never rendered! */}
</body>
</html>
);
}Decide: What Belongs on the Server vs What Truly Needs the Client?
A key skill of modern Next.js development is knowing whether a feature belongs as a default Server Component or requires an explicit "use client" boundary. Classify each feature below:
useState and responds to player click events.The complete lifecycle and architectural hierarchy of a modern Next.js full-stack application:
page.tsx defines publicly viewable UI.layout.tsx wraps child routes with persistent, shared UI without state wipes."use client" when browser interactivity (useState, onClick) is needed.Validate your understanding of the App Router, file-system routing, root and nested layouts, Server vs. Client components, and Link prefetching.