CoachnestCoachnest
Sign InGet Started
Back to course

Next.js 16: The Complete Developer Guide

…
—
Contents
1

What's New in Next.js 16

Reading14mFree
2

Installation, CLI & Your First Project

Reading12mFree
3

Project Structure & Conventions Deep Dive

Reading16m
4

Turbopack — The New Default Bundler

Video18m
5

Configuring TypeScript, ESLint & next.config.ts

Reading14m
6

Chapter 1 — Quiz

Quiz10m
7

App Router Fundamentals

Reading16m
8

Dynamic Routes, Catch-Alls & Type-Safe Params

Reading14m
9

Route Groups & Parallel Routes

Reading16m
10

Intercepting Routes & Modal Patterns

Reading12m
11

Loading, Error & Not-Found UI

Reading12m
12

Chapter 2 — Routing Quiz

Quiz12m
13

Understanding the Server/Client Boundary

Reading18m
14

Choosing When to use "use client"

Reading14m
15

Composing Server & Client Components

Reading14m
16

server-only, client-only & Code Splitting

Reading12m
17

Chapter 3 — Quiz

Quiz10m
18

Fetching Data in Server Components

Reading14m
19

The Next.js 16 Cache Model

Reading16m
20

Revalidation: revalidateTag, revalidatePath & On-Demand

Reading12m
21

Cache Components — Building Reusable Cached Functions

Reading14m
22

Search Params, Cookies & Dynamic APIs

Reading12m
23

Chapter 4 — Quiz

Quiz12m
24

Server Actions From First Principles

Reading16m
25

Forms with useActionState & Progressive Enhancement

Reading14m
26

Optimistic UI with useOptimistic

Reading12m
27

Validation with Zod + Server Actions

Reading12m
28

Chapter 5 — Quiz

Quiz10m
29

Static vs Dynamic vs Streaming

Reading14m
30

generateStaticParams & Pre-Rendering Dynamic Routes

Reading12m
31

Incremental Static Regeneration (ISR)

Reading12m
32

Partial Prerendering (PPR)

Reading16m
33

Edge Runtime vs Node.js Runtime

Reading12m
34

Rendering Strategies Deep Dive

Video22m
35

Chapter 6 — Quiz

Quiz12m
36

Tailwind CSS v4 with Next.js 16

Reading14m
37

CSS Modules, Global Styles & Scoped CSS

Reading10m
38

next/image — Smart, Fast Images

Reading14m
39

Fonts, Icons & Metadata

Reading12m
40

Chapter 7 — Quiz

Quiz10m

Middleware Fundamentals

Reading14m
42

Sessions, JWTs & Cookies

Reading16m
43

Protecting Server Components & Server Actions

Reading12m
44

Chapter 8 — Quiz

Quiz10m
45

Prisma with Next.js — The Production Setup

Reading14m
46

Mutations: Server Actions + Database Writes

Reading12m
47

Route Handlers & REST APIs

Reading12m
48

Chapter 9 — Quiz

Quiz10m
49

Unit & Component Testing with Vitest

Reading12m
50

End-to-End Testing with Playwright

Reading14m
51

Deploying to Vercel

Reading12m
52

Self-Hosting with Docker

Reading14m
53

Production Performance Checklist

Reading12m
54

Final Assessment — Next.js 16 Mastery

Quiz20m
←→navigate lessons
Chapter 8 of 10·Chapter 8 — Authentication & Middleware
Lesson 41 of 54Reading14 min

Middleware Fundamentals

#Middleware Fundamentals¶

Middleware runs before a request reaches a page or route handler. It runs in the Edge runtime, close to the user. Use it for:

  • Authentication & route protection
  • Redirects (locale, A/B tests, legacy URLs)
  • Rewrites (proxy /api to a different service)
  • Adding request headers
  • Bot detection / rate limiting

Anatomy¶

ts
19 lines
1// middleware.ts (project root, sibling of app/)
2import { NextResponse, type NextRequest } from "next/server";
3
4export function middleware(req: NextRequest) {
5  // 1. Inspect the request
6  const isApi = req.nextUrl.pathname.startsWith("/api");
7
8  // 2. Decide what to do
9  if (isApi && !req.headers.get("x-api-key")) {
10    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
11  }
12
13  // 3. Pass through (default)
14  return NextResponse.next();
15}
16
17export const config = {
18  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
19};

The matcher¶

matcher decides which paths run through middleware. Anything outside the matcher skips it.

ts
7 lines
1export const config = {
2  matcher: [
3    "/dashboard/:path*",
4    "/account/:path*",
5    "/api/:path*",
6  ],
7};

Be generous in what to exclude — never run middleware on _next/static, which would 10× your edge invocations.

Three Things You Can Return¶

ts
4 lines
1return NextResponse.next();                                  // continue
2return NextResponse.redirect(new URL("/login", req.url));    // 302
3return NextResponse.rewrite(new URL("/eu", req.url));        // URL unchanged, served from /eu
4return new NextResponse("Forbidden", { status: 403 });        // short-circuit

Reading Cookies¶

ts
1 line
1const token = req.cookies.get("session")?.value;

Middleware can read and write cookies:

ts
3 lines
1const res = NextResponse.next();
2res.cookies.set("visit", String(Date.now()));
3return res;

Forwarding Headers to Pages¶

Add a header in middleware → pages read it via headers():

ts
3 lines
1const res = NextResponse.next();
2res.headers.set("x-pathname", req.nextUrl.pathname);
3return res;
tsx
2 lines
1import { headers } from "next/headers";
2const pathname = (await headers()).get("x-pathname");

Useful for layouts that need to know the current pathname.

A Real-World Middleware¶

ts
32 lines
1import { NextResponse, type NextRequest } from "next/server";
2import { jwtVerify } from "jose";
3
4const PUBLIC = ["/", "/login", "/signup", "/blog"];
5const isPublic = (p: string) => PUBLIC.some((x) => p === x || p.startsWith(`${x}/`));
6
7export async function middleware(req: NextRequest) {
8  const { pathname } = req.nextUrl;
9
10  if (isPublic(pathname)) return NextResponse.next();
11
12  const token = req.cookies.get("session")?.value;
13  if (!token) {
14    const url = req.nextUrl.clone();
15    url.pathname = "/login";
16    url.searchParams.set("next", pathname);
17    return NextResponse.redirect(url);
18  }
19
20  try {
21    await jwtVerify(token, new TextEncoder().encode(process.env.SESSION_SECRET!));
22    return NextResponse.next();
23  } catch {
24    const url = req.nextUrl.clone();
25    url.pathname = "/login";
26    return NextResponse.redirect(url);
27  }
28}
29
30export const config = {
31  matcher: ["/((?!api|_next|favicon.ico).*)"],
32};

What You Can't Do in Middleware¶

  • Use Node-only APIs (fs, crypto's sync APIs, native modules)
  • Run expensive work (> ~50 ms)
  • Read request bodies (use a route handler)
  • Access cookies() from next/headers (use req.cookies instead)

Previous

Chapter 7 — Quiz

Next

Sessions, JWTs & Cookies

Use ← → arrow keys to navigate between lessons