Architecture Overview
Server Runtime
Rendering Pipeline
Client Navigation
Caching and Export
Development Tools
Build and Configuration
Ecosystem Packages
Testing Infrastructure
How It Works
The following files were used as context for generating this wiki page:
Font Optimization (next/font) is a built-in Next.js subsystem engineered to eliminate external network requests for web fonts at runtime while automatically preventing Cumulative Layout Shift (CLS). By default, fetching fonts from external providers like Google Fonts or self-hosting local font files introduces privacy concerns, layout jumps during font loading, and additional DNS round-trips. The next/font package addresses these challenges by shifting font fetching, subset extraction, and metric calculation to build time.
The subsystem comprises two primary loaders: nextFontGoogleFontLoader for Google Fonts and nextFontLocalFontLoader for local font files. During compilation, these loaders download or read font binary buffers, parse metadata using fontkit or precalculated metrics (capsizeFontsMetrics), emit optimized font files into .next/static/media, and automatically inject sizing adjustments (ascent-override, descent-override, line-gap-override, and size-adjust) to match fallback system fonts like Arial or Times New Roman. This ensures zero layout shifts while completely self-hosting web typography.
The Google Fonts loader (nextFontGoogleFontLoader) handles validation, URL construction, remote CSS fetching, binary downloading, and local asset replacement. When invoked during compilation, it validates options against static metadata (googleFontsMetadata), builds a Google Fonts API request URL containing selected weights, styles, and variable axes, and downloads the resulting CSS declarations.
The step-by-step control flow through the Google Fonts loader follows a strict sequence:
validateGoogleFontFunctionCall(): Validates that the requested font family exists, checks requested subsets, weights, and styles against googleFontsMetadata, and returns structured FontOptions.getFontAxes() / getGoogleFontsUrl(): Computes the required font axes and builds the target request URL targeting modern user agents to guarantee .woff2 responses.fetchCSSFromGoogleFonts(): Fetches the CSS payload using a retry mechanism (retry) and in-memory caching (cssCache) to prevent duplicate compilation requests.findFontFilesInCss(): Parses the CSS string line-by-line, tracking subset comment annotations (e.g., /* latin */) to determine whether individual font files match user-specified preload subsets.fetchFontFile() & emitFontFile(): Downloads binary font buffers, caches them via fontCache, and emits them to .next/static/media.fonts.gstatic.com URLs in the CSS string with the emitted local selfHostedFileUrl paths.Sources: packages/font/src/google/loader.ts:28-162, packages/font/src/google/fetch-css-from-google-fonts.ts:12-36, packages/font/src/google/find-font-files-in-css.ts:6-38
The local font loader (nextFontLocalFontLoader) processes self-hosted font arrays specified via next/font/local. It resolves file paths relative to the calling module, reads binary buffers from the filesystem, extracts font metadata using fontkit, and dynamically constructs @font-face CSS declarations.
When multiple font files are provided in the src array, pickFontFileForFallbackGeneration() determines which font file is used to calculate automatic fallback metrics. It evaluates weight distance from normal weight (400), prefers normal style over italic, and breaks ties by choosing the thinner font variant.
Note
If font-family is explicitly declared in the declarations array of a local font call, nextFontLocalFontLoader respects the custom property; otherwise, it automatically assigns the generated variable name as the font-family.
To prevent layout shift when web fonts swap in for fallback fonts, next/font calculates sizing adjustments (size-adjust, ascent-override, descent-override, and line-gap-override). For Google Fonts, getFallbackFontOverrideMetrics() invokes calculateSizeAdjustValues(), which executes the call chain nextFontGoogleFontLoader → getFallbackFontOverrideMetrics → calculateSizeAdjustValues → formatName to normalize the font family string, look up metrics in capsizeFontsMetrics, compute proportion factors, and format override percentages. For local fonts, getFallbackMetricsFromFontFile() uses fontkit to inspect glyph metrics and compute average character widths (calcAverageWidth).
Sources: packages/font/src/google/get-fallback-font-override-metrics.ts:13-27, packages/next/src/server/font-utils.ts:6-44
Sources: packages/font/src/local/get-fallback-metrics-from-font-file.ts:73-95, packages/next/src/server/font-utils.ts:19-44
Warning
Character average width calculation (calcAverageWidth) currently evaluates a fixed sample string (aaabcdeeeefghiijklmnnoopqrrssttuvwxyz ) designed specifically for the Latin alphabet. Non-Latin alphabets may fail character coverage checks and skip automatic size-adjust calculations.
Sources: packages/font/src/google/loader.ts:13-92, packages/font/src/google/get-fallback-font-override-metrics.ts:7-12
Next.js provides ESLint rules in @next/eslint-plugin-next to enforce font optimization best practices and prevent misconfigurations.
no-page-custom-font: Prevents adding Google Fonts via manual <link> tags inside custom pages or pages/_document.js, ensuring automatic optimization is not bypassed.google-font-display: Enforces font-display configuration on Google Font link tags, recommending &display=optional and flagging unoptimized display settings like auto, block, or fallback.Sources: packages/eslint-plugin-next/src/rules/no-page-custom-font.ts:152-167, packages/eslint-plugin-next/src/rules/google-font-display.ts:39-50
The following example demonstrates how to configure and use optimized Google and local fonts in a Next.js application:
import { Inter, Oswald } from 'next/font/google'
import localFont from 'next/font/local'
// Configure Google Font with subsets and variable styling
const inter = Inter({
subsets: ['latin'],
display: 'swap',
variable: '--font-inter',
})
// Configure Local Font with custom fallback metrics
const myFont = localFont({
src: './my-font.woff2',
display: 'swap',
adjustFontFallback: 'Arial',
})
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className={`${inter.variable}`}>
<body className={myFont.className}>
{children}
</body>
</html>
)
}Sources: packages/next-codemod/transforms/testfixtures/built-in-next-font/page.output.tsx:3-18, packages/font/src/local/index.ts:9-25