next/font: self-hosted, zero-layout-shift fonts
The traditional way to use a Google Font — a <link> tag pointing at Google's own CDN in the document head — costs a real, visible performance hit: an extra DNS lookup and connection to a third-party host, before the font file itself even starts downloading. next/font removes that entirely.
Loading a font
// app/layout.tsx
import { Inter } from "next/font/google";
const inter = Inter({ subsets: ["latin"] });
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className={inter.className}>
<body>{children}</body>
</html>
);
}Despite Inter being imported from next/font/google, no request to Google's servers happens at runtime at all — Next.js downloads the font file at build time and serves it directly from the same origin as the rest of the site, alongside every other static asset. subsets: ["latin"] limits which character set actually gets downloaded, keeping the font file smaller than shipping every language the typeface supports.
Why this avoids layout shift
A traditionally-loaded web font causes a Flash of Unstyled Text (or invisible text) while it downloads — text first renders in a fallback system font, then visibly reflows once the real font arrives, which is exactly the kind of layout instability Core Web Vitals penalizes. next/font calculates a fallback font with matching metrics (roughly the same width and height per character) automatically, so the page never visibly jumps once the real font loads in — this is a real, measurable Cumulative Layout Shift improvement, not just faster loading.
A local, self-hosted font file
// app/layout.tsx
import localFont from "next/font/local";
const brandFont = localFont({
src: "./fonts/Brand-Regular.woff2",
variable: "--font-brand",
});next/font/local covers a custom font file that isn't on Google Fonts at all — same self-hosting and layout-shift protection, pointed at a file already in the project instead of downloaded from Google at build time.
Using it as a CSS variable instead
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });/* app/globals.css */
body {
font-family: var(--font-inter), system-ui, sans-serif;
}Setting variable instead of applying .className directly exposes the font as a CSS custom property — useful when a CSS Module (part 19) needs to reference the font rather than relying on inheritance from a class applied way up on <html>.
Adding a Google Fonts <link> tag directly in the document head out of habit, alongside or instead of next/font/google. It works, but it's exactly the extra third-party connection and layout-shift risk next/font exists to eliminate — inside a Next.js project, there's no real reason to reach for the traditional <link> approach at all.
The blog itself is functionally and visually complete. Next: making sure search engines can actually find every page — a real sitemap and robots.txt, generated from the same data the rest of the site already uses.