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

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
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 7 of 10·Chapter 7 — Styling, Assets & Performance
Lesson 39 of 54Reading12 min

Fonts, Icons & Metadata

#Fonts, Icons & Metadata¶

next/font — Self-Hosted Fonts, Zero CLS¶

tsx
22 lines
1// app/layout.tsx
2import { Inter, JetBrains_Mono } from "next/font/google";
3
4const inter = Inter({
5  subsets: ["latin"],
6  display: "swap",
7  variable: "--font-sans",
8});
9
10const mono = JetBrains_Mono({
11  subsets: ["latin"],
12  display: "swap",
13  variable: "--font-mono",
14});
15
16export default function RootLayout({ children }: { children: React.ReactNode }) {
17  return (
18    <html lang="en" className={`${inter.variable} ${mono.variable}`}>
19      <body>{children}</body>
20    </html>
21  );
22}

At build time, Next.js downloads the font files and serves them from your own domain — no Google CDN call from the user's browser. Faster, more private, no CLS.

Local Fonts¶

tsx
9 lines
1import localFont from "next/font/local";
2
3const display = localFont({
4  src: [
5    { path: "./fonts/Display-Regular.woff2", weight: "400" },
6    { path: "./fonts/Display-Bold.woff2", weight: "700" },
7  ],
8  variable: "--font-display",
9});

Icons — Lucide is the Default¶

bash
1 line
1npm i lucide-react
tsx
3 lines
1import { Search, ArrowRight } from "lucide-react";
2
3<Search className="h-5 w-5 text-gray-500" />

Tree-shakes per icon — you don't pay for the whole library.

Metadata API — Static Defaults¶

tsx
17 lines
1// app/layout.tsx
2import type { Metadata } from "next";
3
4export const metadata: Metadata = {
5  metadataBase: new URL("https://coachnest.dev"),
6  title: { default: "CoachNest", template: "%s — CoachNest" },
7  description: "A modern learning platform.",
8  openGraph: {
9    siteName: "CoachNest",
10    type: "website",
11    locale: "en_US",
12  },
13  twitter: {
14    card: "summary_large_image",
15    creator: "@coachnest",
16  },
17};

Per-page override:

ts
5 lines
1// app/about/page.tsx
2export const metadata: Metadata = {
3  title: "About us",            // → "About us — CoachNest" via the template
4  description: "Who we are.",
5};

Dynamic Metadata¶

ts
12 lines
1// app/courses/[slug]/page.tsx
2export async function generateMetadata({ params }): Promise<Metadata> {
3  const { slug } = await params;
4  const course = await getCourse(slug);
5  if (!course) return { title: "Course not found" };
6
7  return {
8    title: course.title,
9    description: course.shortDesc,
10    openGraph: { images: [course.thumbnail] },
11  };
12}

OG Image Generation¶

Drop opengraph-image.tsx in any segment:

tsx
19 lines
1// app/courses/[slug]/opengraph-image.tsx
2import { ImageResponse } from "next/og";
3
4export const runtime = "edge";
5export const size = { width: 1200, height: 630 };
6export const contentType = "image/png";
7
8export default async function og({ params }: { params: { slug: string } }) {
9  const course = await getCourse(params.slug);
10  return new ImageResponse(
11    (
12      <div style={{ fontSize: 64, background: "#0a0a0a", color: "white", width: "100%", height: "100%", padding: 60 }}>
13        <p style={{ opacity: 0.7, fontSize: 28 }}>CoachNest</p>
14        <h1>{course?.title}</h1>
15      </div>
16    ),
17    { ...size },
18  );
19}

A fresh OG image per course, rendered at the edge — beautifully scalable.

Sitemap & Robots¶

ts
12 lines
1// app/sitemap.ts
2export default async function sitemap() {
3  const courses = await db.course.findMany({ select: { slug: true, updatedAt: true } });
4  return [
5    { url: "https://coachnest.dev", lastModified: new Date(), priority: 1.0 },
6    ...courses.map((c) => ({
7      url: `https://coachnest.dev/courses/${c.slug}`,
8      lastModified: c.updatedAt,
9      priority: 0.7,
10    })),
11  ];
12}
ts
7 lines
1// app/robots.ts
2export default function robots() {
3  return {
4    rules: [{ userAgent: "*", allow: "/", disallow: "/api/" }],
5    sitemap: "https://coachnest.dev/sitemap.xml",
6  };
7}

Drop the files; Next.js routes /sitemap.xml and /robots.txt automatically.

Previous

next/image — Smart, Fast Images

Next

Chapter 7 — Quiz

Use ← → arrow keys to navigate between lessons