How it works
The explanation, with examples you can run.
Images
import Image from "next/image"import hero from "./hero.jpg" // static import: width, height and blur placeholder known export default function Home() { return ( <> <Image src={hero} alt="Our team at work" preload placeholder="blur" sizes="100vw" /> <Image src="https://cdn.example.com/p/42.jpg" alt="Product 42" width={400} height={300} /> </> )}- The optimiser resizes on request and caches results; the browser picks a size from the generated
srcset. Givesizesfor responsive images, or the browser may download a larger file than it shows. - Images load lazily unless you say otherwise. Mark the one LCP image with
preload(Next.js 16 deprecatedpriorityfor it). - Remote hosts must be allowed in
images.remotePatterns;images.domainsis deprecated. Next.js 16 also tightened defaults: only quality 75 is allowed unless you listimages.qualities, local IP addresses are blocked to avoid SSRF, and at most three redirects are followed.
Fonts
// app/layout.tsximport { Inter } from "next/font/google"const inter = Inter({ subsets: ["latin"], display: "swap" }) export default function RootLayout({ children }: { children: React.ReactNode }) { return <html lang="en" className={inter.className}><body>{children}</body></html>}The font files are downloaded during next build and served as static assets from your domain, with a size-adjusted fallback so text doesn't jump when the web font arrives. Because of that download, a build without internet access fails. Building this path's probe app in a sandbox stopped with "Failed to fetch Geist from Google Fonts" until the font import was removed. Use next/font/local with a checked-in file for offline or locked-down CI.
The build
next build compiles with Turbopack, type-checks, prerenders routes, and prints a table where ○ is static, ◐ is a partial prerender, and ƒ is rendered per request, with the revalidate and expire times of cached routes. Read it after every significant change; a route turning ƒ is a performance regression you can see before shipping. A custom webpack function in next.config makes the default build fail on purpose; migrate it to turbopack options or build with --webpack.
Output in .next/static has content-hashed names, and Next.js serves it as public, max-age=31536000, immutable; a deploy changes the names, so nothing needs purging.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.