Dev Logs
/Next.js/ Chapter 1: Introduction & Setup
Chapters
  • 01Chapter 1: Introduction & Setup
    • Plain English Explanation
    • The one thing you must understand before anything else
    • Which version is this book?
    • What Next.js gives you
    • . File-system routing
    • . Server Components by default
    • . A build system you don't configure
    • . Built-in optimizations
    • . A server, when you want one
    • Requirements
    • Creating a project
    • What you just got
    • Turbopack is now the default
    • The four commands
    • A note on AI assistants
    • Common Pitfalls
    • . Following a Pages Router tutorial by accident
    • . Expecting useState to work in a page by default
    • . Running on Node 18
    • . A stale --turbopack flag with a webpack config
    • . Forgetting <html> and <body> in the root layout
    • When & Why to Use Next.js
    • Reach for Next.js when you need:
    • Reach for something else when:
    • Mini Practice Problems
    • Problem 1: Spot the router
    • Problem 2: Fix the version
    • Problem 3: Build the smallest app
    • Problem 4: Read the error
    • Interview Notes
    • Common Questions
    • Asked at Companies
    • Visual Memory Aid
    • Key Takeaways
  • 02Chapter 2: Project Structure & Configuration
  • 03Chapter 3: Layouts & Pages
  • 04Chapter 4: Linking & Navigation
  • 05Chapter 5: Dynamic Routes & Params
  • 06Chapter 6: Route Groups & Organization
  • 07Chapter 7: Parallel & Intercepting Routes
  • 08Chapter 8: Loading, Suspense & Streaming
  • 09Chapter 9: Error Handling
  • 10Chapter 10: Server & Client Components
  • 11Chapter 11: Data Fetching
  • 12Chapter 12: Server Actions & Mutations
  • 13Chapter 13: Route Handlers
  • 14Chapter 14: Caching & use cache
  • 15Chapter 15: Revalidation & ISR
  • 16Chapter 16: Cache Components & Partial Prerendering
  • 17Chapter 17: Proxy (formerly Middleware)
  • 18Chapter 18: Authentication & Authorization
  • 19Chapter 19: Metadata, SEO & OG Images
  • 20Chapter 20: Images & Fonts
  • 21Chapter 21: Styling
  • 22Chapter 22: Performance Optimization
  • 23Chapter 23: Testing
  • 24Chapter 24: Deployment & Self-Hosting
  • 25Chapter 25: Upgrading to Next.js 16
  • 26Chapter 26: Capstone Project
  • 27Chapter 27: React Performance Profiling
All chapters

🚀 Chapter 1: Introduction & Setup

Understanding what Next.js actually is, why the App Router replaced everything you may have read online, and getting a Next.js 16 project running from zero.

📖 Plain English Explanation

React gives you a way to build user interfaces. That's all it gives you. It does not tell you how to route between pages, how to fetch data on a server, how to bundle your code, how to optimize images, or how to deploy.

Next.js is React plus all the answers to those questions. It is a framework built on top of React that makes the boring-but-essential decisions for you.

Think of it like this:

  • React = an engine. Powerful, but you can't drive an engine.
  • Next.js = the whole car. Engine, chassis, steering, brakes, dashboard.

You can build the rest of the car yourself (Vite + React Router + TanStack Query + your own server). Many teams do. Next.js is for when you'd rather write features than assemble a car.

The one thing you must understand before anything else

Next.js has two routers, and they are completely different frameworks wearing the same name:

Pages RouterApp Router
Folderpages/app/
Introduced2016Next.js 13 (2022), stable in 14
Data fetchinggetServerSideProps, getStaticPropsasync components, fetch
ComponentsAll client componentsServer Components by default
Status in 2026Maintenance modeThe only one being developed

This book covers the App Router exclusively. Not because Pages Router is bad, but because it is finished — it receives security fixes and nothing else. Every new Next.js feature since 2023 (Server Components, Server Actions, streaming, Partial Prerendering, Cache Components) exists only in the App Router.

If you find a tutorial that says getServerSideProps, _app.js, or pages/api/hello.js — that tutorial is teaching the old framework. Close it.

🕰️ Which version is this book?

Next.js 16.3 (released 3 August 2026). This matters more than it usually does.

Next.js 16 (October 2025) was a large breaking release. A very large fraction of the Next.js content on the internet — blog posts, YouTube courses, Stack Overflow answers, and the training data inside AI assistants — describes Next.js 14 or 15. Following it will produce code that does not compile.

Here is the short list of what changed, so you can immediately recognize outdated material:

Old (Next 14/15)New (Next 16)
middleware.tsproxy.ts
const { slug } = paramsconst { slug } = await params
cookies() returns storeawait cookies()
experimental: { ppr: true }cacheComponents: true
revalidateTag('posts')revalidateTag('posts', 'max')
unstable_cacheLifecacheLife
next dev --turbopacknext dev (Turbopack is the default)
next lintESLint / Biome directly
serverRuntimeConfigenvironment variables
import Image from 'next/legacy/image'import Image from 'next/image'

Every chapter in this book flags these with a ⚠️ Changed in Next.js 16 callout so you can spot them at a glance.

🧱 What Next.js gives you

1. File-system routing

You create a file, you get a URL. No route configuration object anywhere.

app/page.tsx              →  /
app/about/page.tsx        →  /about
app/blog/[slug]/page.tsx  →  /blog/hello-world

2. Server Components by default

In a plain React app, every component ships to the browser as JavaScript. In the App Router, components run on the server unless you opt them into the browser. This means you can talk to a database directly inside a component:

tsx
// app/page.tsx — this code never reaches the browser
import { db } from '@/lib/db'

export default async function Page() {
  const users = await db.user.findMany()
  return <ul>{users.map((u) => <li key={u.id}>{u.name}</li>)}</ul>
}
jsx
// app/page.js — this code never reaches the browser
import { db } from '@/lib/db'

export default async function Page() {
  const users = await db.user.findMany()
  return <ul>{users.map((u) => <li key={u.id}>{u.name}</li>)}</ul>
}

Notice: an async component. That is not possible in client-side React. Chapter 10 covers why.

3. A build system you don't configure

Bundling, code splitting, minification, TypeScript compilation, CSS handling, and tree shaking are all set up. Since Next.js 16, the bundler is Turbopack (written in Rust), and it is on by default.

4. Built-in optimizations

  • next/image — automatic resizing, modern formats, lazy loading
  • next/font — self-hosted fonts with zero layout shift
  • next/link — prefetching and instant client-side navigation
  • Automatic code splitting per route

5. A server, when you want one

Route Handlers give you API endpoints. Server Actions let you mutate data from a form without writing an API at all.

🛠️ Requirements

Next.js 16 raised its floor. Check these before you start:

bash
node --version   # must be 20.9.0 or newer (Node 18 is no longer supported)
RequirementMinimum
Node.js20.9.0 (LTS)
TypeScript5.1.0
React19.2
Chrome / Edge / Firefox111+
Safari16.4+

If you're on Node 18, upgrade first — Next.js 16 will refuse to run.

bash
# with nvm
nvm install 22
nvm use 22

📦 Creating a project

The official scaffolder is create-next-app. Run it with your package manager of choice:

bash
# npm
npx create-next-app@latest my-app

# pnpm
pnpm create next-app my-app

# yarn
yarn create next-app my-app

# bun
bun create next-app my-app

You'll be asked a series of questions:

✔ Would you like to use TypeScript?             › Yes
✔ Which linter would you like to use?           › ESLint
✔ Would you like to use Tailwind CSS?           › Yes
✔ Would you like your code inside a `src/` directory? › No
✔ Would you like to use App Router?             › Yes   ← say Yes
✔ Would you like to use Turbopack?              › Yes
✔ Would you like to customize the import alias? › No

The only answer that really matters is App Router: Yes. Everything else is preference.

To skip the prompts entirely:

bash
npx create-next-app@latest my-app --typescript --tailwind --app --no-src-dir --import-alias "@/*"

Then:

bash
cd my-app
npm run dev

Open http://localhost:3000. You have a running Next.js app.

📁 What you just got

my-app/
├── app/
│   ├── favicon.ico
│   ├── globals.css       # global stylesheet
│   ├── layout.tsx        # root layout — wraps every page
│   └── page.tsx          # the / route
├── public/               # static files served at /
├── next.config.ts        # framework configuration
├── package.json
├── tsconfig.json
└── eslint.config.mjs

Two files do all the work right now.

app/layout.tsx — the root layout. It renders on every single page and must contain <html> and <body>:

tsx
// app/layout.tsx
import type { Metadata } from 'next'
import './globals.css'

export const metadata: Metadata = {
  title: 'My App',
  description: 'Built with Next.js',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}
jsx
// app/layout.js
import './globals.css'

export const metadata = {
  title: 'My App',
  description: 'Built with Next.js',
}

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}

app/page.tsx — the UI for /:

tsx
// app/page.tsx
export default function Page() {
  return <h1>Hello, Next.js 16</h1>
}
jsx
// app/page.js
export default function Page() {
  return <h1>Hello, Next.js 16</h1>
}

Both files are identical in TypeScript and JavaScript apart from the type annotations.

⚡ Turbopack is now the default

⚠️ Changed in Next.js 16

Turbopack went stable and became the default bundler for both next dev and next build. The --turbopack flag is no longer needed.

json
// package.json — Next.js 15 (old)
{
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build --turbopack",
    "start": "next start"
  }
}
json
// package.json — Next.js 16 (current)
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}

Turbopack also caches compiler output to disk between runs (filesystem caching), so the second next dev of the day starts far faster than the first.

If you have a custom webpack config, next build will now fail on purpose, to stop you silently ignoring it. Three ways out:

bash
next build --turbopack   # use Turbopack, ignore the webpack config
next build --webpack     # opt out of Turbopack entirely

...or migrate the config to the top-level turbopack option (Chapter 2).

🧭 The four commands

bash
next dev      # development server with hot reload
next build    # production build
next start    # serve the production build (run build first)
next typegen  # generate route types (PageProps, LayoutProps, RouteContext)

⚠️ Changed in Next.js 16

next lint was removed. next build no longer runs linting either. Run ESLint or Biome directly:

json
{
  "scripts": {
    "lint": "eslint ."
  }
}

A codemod handles the migration: npx @next/codemod@canary next-lint-to-eslint-cli .

⚠️ Changed in Next.js 16

next dev and next build now write to separate output directories (next dev uses .next/dev), so you can run both at once. A lockfile also prevents two next dev processes fighting over the same project.

🤖 A note on AI assistants

Next.js 16 ships a genuinely useful feature for this exact problem: it can generate an AGENTS.md file that points your AI coding assistant at the version-matched docs bundled inside node_modules/next/dist/docs/.

bash
npx @next/codemod@canary agents-md

The generated block says, bluntly:

This is NOT the Next.js you know. This version has breaking changes — APIs, conventions, and file structure may all differ from your training data.

If you use Copilot, Cursor, or Claude Code on a Next.js project, run this. It is the difference between an assistant that writes middleware.ts and one that writes proxy.ts.

⚠️ Common Pitfalls

1. Following a Pages Router tutorial by accident

❌ pages/index.js              ← Pages Router
❌ getServerSideProps()        ← Pages Router
❌ pages/api/users.js          ← Pages Router
❌ _app.js / _document.js      ← Pages Router

✅ app/page.tsx                ← App Router
✅ async function Page()       ← App Router
✅ app/api/users/route.ts      ← App Router
✅ app/layout.tsx              ← App Router

Fix: if the tutorial mentions a pages/ folder, it is teaching a different framework.

2. Expecting useState to work in a page by default

tsx
// ❌ app/counter/page.tsx — this crashes
export default function Page() {
  const [count, setCount] = useState(0)  // Error: useState only works in Client Components
  return <button onClick={() => setCount(count + 1)}>{count}</button>
}
tsx
// ✅ app/counter/page.tsx
'use client'
import { useState } from 'react'

export default function Page() {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount(count + 1)}>{count}</button>
}

Fix: hooks and event handlers need 'use client' at the top of the file. Chapter 10 explains the boundary in depth.

3. Running on Node 18

error - Next.js requires Node.js 20.9.0 or later

Fix: nvm install 22 && nvm use 22.

4. A stale --turbopack flag with a webpack config

If a plugin injects a webpack option into your config, next build fails with "a webpack configuration was found" even though you never wrote one.

Fix: find the plugin, or run next build --webpack while you migrate.

5. Forgetting <html> and <body> in the root layout

tsx
// ❌ app/layout.tsx
export default function RootLayout({ children }) {
  return <div>{children}</div>   // Error: missing <html> and <body>
}

The root layout is the only place these tags exist. Next.js will not add them for you.

🎯 When & Why to Use Next.js

Reach for Next.js when you need:

✅ SEO — content rendered on the server, indexable by crawlers
✅ Fast first paint — HTML arrives ready, not assembled by JS
✅ A backend and frontend in one codebase
✅ Content that changes (blogs, docs, e-commerce, dashboards)
✅ A team that would rather ship features than configure tooling

Reach for something else when:

❌ You're building a pure SPA behind a login with no SEO needs
   → Vite + React Router is lighter and simpler
❌ You're building a static marketing site with no interactivity
   → Astro ships less JavaScript
❌ You need a mobile app
   → React Native / Expo
❌ Your team is deeply invested in a different backend
   → Next.js can still be the frontend, but you lose half the value

Being honest about this matters. Next.js is not automatically the right answer, and "we used Next.js because it's popular" is how teams end up fighting a framework instead of using it.

🏋️ Mini Practice Problems

Problem 1: Spot the router

For each snippet, say whether it's Pages Router or App Router:

jsx
// A
export async function getStaticProps() {
  return { props: { posts: [] } }
}

// B
export default async function Page() {
  const posts = await getPosts()
  return <PostList posts={posts} />
}

// C
export default function handler(req, res) {
  res.status(200).json({ name: 'John' })
}

// D
export async function GET() {
  return Response.json({ name: 'John' })
}

Problem 2: Fix the version

This code was written for Next.js 15. Update it for Next.js 16:

tsx
// app/blog/[slug]/page.tsx
export default function Page({ params }: { params: { slug: string } }) {
  return <h1>{params.slug}</h1>
}

Problem 3: Build the smallest app

From an empty folder, create the minimum set of files needed for http://localhost:3000/hello to render the text "Hello". How many files is it? (Answer: three — package.json, app/layout.tsx, app/hello/page.tsx.)

Problem 4: Read the error

You run next build and get:

Error: Turbopack build failed because a webpack configuration was found

You have never written a webpack config. List two possible causes and two fixes.

💼 Interview Notes

Common Questions

Q: What problem does Next.js solve that React doesn't? React is a view library — it renders components. Next.js adds routing, server rendering, data fetching, bundling, image/font optimization, and a deployment story. React tells you how to draw; Next.js tells you how to ship.

Q: What is the difference between the Pages Router and the App Router? The Pages Router renders everything as Client Components and fetches data through special exported functions (getServerSideProps, getStaticProps). The App Router is built on React Server Components: components run on the server by default, data is fetched with plain async/await inside components, and UI can stream in pieces. The Pages Router is in maintenance mode.

Q: What are the rendering strategies in Next.js?

  • Static (SSG) — HTML generated at build time
  • Dynamic (SSR) — HTML generated per request
  • ISR — static HTML regenerated on a schedule or on demand
  • Partial Prerendering (PPR) — a static shell with dynamic holes streamed in, now delivered through Cache Components
  • Client-side — rendered in the browser after hydration

Q: Why did Next.js switch to Turbopack? Webpack is written in JavaScript and re-does work on every change. Turbopack is written in Rust, does incremental compilation, and caches to disk. Result: much faster cold starts and hot updates, especially on large apps.

Q: Is Next.js only for Vercel? No. output: 'standalone' produces a self-contained Node server you can run in Docker anywhere. Some features (ISR at the edge, image optimization at scale) are easier on Vercel, but nothing is locked in. Chapter 24 covers self-hosting.

🏢 Asked at Companies

  • Vercel: "Walk me through what happens between a user clicking a <Link> and the new page appearing."
  • Netflix: "When would you choose the App Router over a plain SPA, and when would you not?"
  • Shopify: "How do you decide between static generation and server rendering for a product page?"
  • Stripe: "What is the actual cost of adding 'use client' to a component?"

📊 Visual Memory Aid

                    THE NEXT.JS STACK

  ┌─────────────────────────────────────────────┐
  │  Your app                                   │
  │  app/page.tsx, app/layout.tsx, components/  │
  ├─────────────────────────────────────────────┤
  │  Next.js 16                                 │
  │  ├─ Routing        (file system)            │
  │  ├─ Rendering      (RSC, streaming, PPR)    │
  │  ├─ Data           (fetch, cache, actions)  │
  │  ├─ Optimization   (image, font, script)    │
  │  └─ Bundling       (Turbopack)              │
  ├─────────────────────────────────────────────┤
  │  React 19.2                                 │
  │  Server Components, Suspense, Transitions   │
  ├─────────────────────────────────────────────┤
  │  Node.js 20.9+                              │
  └─────────────────────────────────────────────┘


                  TWO ROUTERS, ONE NAME

   pages/  ──────────►  maintenance mode, do not learn
   app/    ──────────►  everything in this book

🎯 Key Takeaways

  1. Next.js is React plus routing, rendering, data, and build tooling — it makes the decisions React deliberately leaves open.
  2. Only the App Router matters. The Pages Router still runs, but receives no new features. If a tutorial has a pages/ folder, skip it.
  3. Next.js 16 broke a lot of what's written online — async params, proxy.ts, cacheComponents, revalidateTag(tag, profile). Watch for the ⚠️ callouts.
  4. Turbopack is the default bundler now. Drop --turbopack from your scripts; keep a webpack config only if you deliberately opt out with --webpack.
  5. Node 20.9+ and TypeScript 5.1+ are hard requirements. Check before you scaffold, not after.

Next Chapter: Project Structure & Configuration →

Practice: Scaffold a fresh app with create-next-app, delete everything inside app/page.tsx, and rebuild it from memory. Then add app/about/page.tsx and navigate between them.


NextChapter 2: Project Structure & Configuration

Open source, free forever. Built by iammhador.

Contribute on GitHub