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
41

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

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 9 of 10·Chapter 9 — Database Integration & APIs
Lesson 47 of 54Reading12 min

Route Handlers & REST APIs

#Route Handlers & REST APIs¶

Server Actions cover most mutations. Use Route Handlers when you need:

  • A public, callable HTTP endpoint (mobile app, third-party integration)
  • Webhooks (Stripe, GitHub, Clerk)
  • File uploads with streaming
  • Custom auth schemes (API keys, OAuth bearer tokens)
  • Non-HTML responses (RSS, sitemaps, OG images, PDFs)

Anatomy¶

ts
18 lines
1// app/api/courses/route.ts
2import { NextRequest } from "next/server";
3
4export async function GET(req: NextRequest) {
5  const q = req.nextUrl.searchParams.get("q") ?? "";
6  const courses = await db.course.findMany({
7    where: { title: { contains: q, mode: "insensitive" } },
8    select: { id: true, title: true, slug: true },
9    take: 20,
10  });
11  return Response.json(courses);
12}
13
14export async function POST(req: NextRequest) {
15  const body = await req.json();
16  // … validate, auth, create
17  return Response.json({ id: "new-id" }, { status: 201 });
18}

All HTTP Verbs Supported¶

GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS — each is a named export.

Dynamic Params¶

ts
7 lines
1// app/api/courses/[id]/route.ts
2export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
3  const { id } = await params;
4  const course = await db.course.findUnique({ where: { id } });
5  if (!course) return Response.json({ error: "Not found" }, { status: 404 });
6  return Response.json(course);
7}

Webhooks — Verifying Signatures¶

ts
24 lines
1// app/api/webhooks/stripe/route.ts
2import Stripe from "stripe";
3
4const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
5
6export async function POST(req: NextRequest) {
7  const sig = req.headers.get("stripe-signature");
8  if (!sig) return new Response("Missing signature", { status: 400 });
9
10  const body = await req.text();   // .text() — Stripe needs the raw body
11  let event: Stripe.Event;
12  try {
13    event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
14  } catch (e) {
15    return new Response("Invalid signature", { status: 400 });
16  }
17
18  if (event.type === "checkout.session.completed") {
19    const s = event.data.object as Stripe.Checkout.Session;
20    await fulfillOrder(s.metadata!.orderId);
21  }
22
23  return new Response("ok");
24}

Streaming Responses¶

ts
19 lines
1export async function GET() {
2  const encoder = new TextEncoder();
3  const stream = new ReadableStream({
4    async start(controller) {
5      for (let i = 0; i < 10; i++) {
6        controller.enqueue(encoder.encode(`data: tick ${i}\n\n`));
7        await new Promise((r) => setTimeout(r, 500));
8      }
9      controller.close();
10    },
11  });
12  return new Response(stream, {
13    headers: {
14      "Content-Type": "text/event-stream",
15      "Cache-Control": "no-cache",
16      Connection: "keep-alive",
17    },
18  });
19}

Server-Sent Events for live dashboards, LLM token streams, build logs.

CORS¶

ts
9 lines
1export async function OPTIONS() {
2  return new Response(null, {
3    headers: {
4      "Access-Control-Allow-Origin": "https://your-mobile-app.com",
5      "Access-Control-Allow-Methods": "GET, POST",
6      "Access-Control-Allow-Headers": "Content-Type, Authorization",
7    },
8  });
9}

For SaaS-style APIs called from arbitrary origins, allow * (and don't accept cookies).

Rate Limiting¶

ts
14 lines
1import { Ratelimit } from "@upstash/ratelimit";
2import { Redis } from "@upstash/redis";
3
4const limit = new Ratelimit({
5  redis: Redis.fromEnv(),
6  limiter: Ratelimit.slidingWindow(10, "1 m"),
7});
8
9export async function POST(req: NextRequest) {
10  const ip = req.headers.get("x-forwarded-for") ?? "anon";
11  const { success } = await limit.limit(ip);
12  if (!success) return new Response("Too many requests", { status: 429 });
13  // …
14}

Previous

Mutations: Server Actions + Database Writes

Next

Chapter 9 — Quiz

Use ← → arrow keys to navigate between lessons