~/TechPurAI
~/tutorials/nextjs-from-scratch/next-font
intermediate·part 20 of 22·2 min read

next/font: self-hosted, zero-layout-shift fonts

Updated Aug 16, 2026JavaScript · Next.js

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

tsx
// 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

tsx
// 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

tsx
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
css
/* 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>.

Common mistake

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.

VK

Vijay Kumar

Founder of TechPurAI — writing hands-on tutorials and honest tool breakdowns.

LinkedIn ↗
← previous19. Styling: CSS Modules and global stylesnext →21. Generating a sitemap and robots.txt