# How to Optimize Next.js Fonts to Prevent Layout Shifts and Speed Up Loading

> Optimize Next.js fonts with next/font for faster loading and zero layout shifts. Automatically preload assets and inject optimized CSS for a seamless user experience.

- Repository: [Vercel/next.js](https://github.com/vercel/next.js)
- Tags: performance
- Published: 2026-02-16

---

**Use the built-in `next/font` package to automatically generate fallback font metrics, preload critical assets, and inject optimized CSS that eliminates Cumulative Layout Shift (CLS) while ensuring text remains visible during load.**

Managing **Next.js fonts** properly requires more than just adding a `<link>` tag to your document head. The `next/font` package in the vercel/next.js repository provides a comprehensive build-time optimization system that automatically eliminates Cumulative Layout Shift (CLS) and accelerates loading through intelligent preloading and fallback generation. By leveraging the source code in `packages/font/src`, you can implement zero-configuration font loading that outperforms manual implementations.

## Understanding the `next/font` Architecture

The font optimization system resides in `packages/font/src` and operates through three core mechanisms that work at build time to prevent runtime performance issues.

### Automatic Fallback Metric Generation

To prevent Cumulative Layout Shift (CLS), Next.js extracts precise font metrics directly from font files during the build process. The [`get-fallback-metrics-from-font-file.ts`](https://github.com/vercel/next.js/blob/main/get-fallback-metrics-from-font-file.ts) utility reads binary font data to calculate **ascent**, **descent**, **line-gap**, and **size-adjust** values. These metrics generate a temporary `@font-face` rule that reserves exact dimensional space in the browser before the actual font downloads, ensuring content does not shift when the custom font renders.

### Built-in Preloading Strategy

When you import a font through `next/font/google` or `next/font/local`, the loader automatically injects a `<link rel="preload">` tag into the document head. In [`packages/font/src/google/loader.ts`](https://github.com/vercel/next.js/blob/main/packages/font/src/google/loader.ts), the system constructs optimized variable font URLs when possible, reducing multiple HTTP requests to a single file fetch. This guarantees the browser discovers and downloads font assets as early as possible during page load.

### Strict Validation and Error Handling

The system validates all font configuration through schema checks in [`validate-google-font-function-call.ts`](https://github.com/vercel/next.js/blob/main/validate-google-font-function-call.ts) and [`validate-local-font-function-call.ts`](https://github.com/vercel/next.js/blob/main/validate-local-font-function-call.ts). These validators throw descriptive `NextFontError` instances for misconfigurations, preventing silent failures that could trigger additional network requests or missing font assets.

## Implementing Google Fonts with Zero Configuration

The most common approach uses `next/font/google` to load fonts from Google Fonts with automatic optimization. The loader handles variable font detection, subsetting, and fallback generation without manual intervention.

```typescript
// app/layout.tsx
import { Inter } from 'next/font/google';

const inter = Inter({
  subsets: ['latin'],
  weight: ['400', '700'],
  fallback: ['Helvetica', 'Arial', 'sans-serif'],
});

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={inter.className}>
      <body>{children}</body>
    </html>
  );
}

```

When this code executes at build time, the loader in [`packages/font/src/google/loader.ts`](https://github.com/vercel/next.js/blob/main/packages/font/src/google/loader.ts) fetches the Google CSS, extracts axis data for variable fonts, and computes fallback metrics. The system emits a compact `@font-face` declaration with `font-display: optional` (as defined in [`packages/font/src/constants.ts`](https://github.com/vercel/next.js/blob/main/packages/font/src/constants.ts)) and injects the preload tag automatically.

## Self-Hosting Local Fonts for Full Control

For proprietary or custom typefaces, `next/font/local` processes self-hosted font files with the same optimization pipeline, reading binary data to generate metrics.

```typescript
// app/layout.tsx
import localFont from 'next/font/local';

const myFont = localFont({
  src: [
    {
      path: '../public/fonts/MyFont-Regular.woff2',
      weight: '400',
      style: 'normal',
    },
    {
      path: '../public/fonts/MyFont-Bold.woff2',
      weight: '700',
      style: 'normal',
    },
  ],
  fallback: ['system-ui'],
});

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={myFont.className}>
      <body>{children}</body>
    </html>
  );
}

```

The [`packages/font/src/local/loader.ts`](https://github.com/vercel/next.js/blob/main/packages/font/src/local/loader.ts) reads each `.woff2` file specified in the `src` array, invokes [`get-fallback-metrics-from-font-file.ts`](https://github.com/vercel/next.js/blob/main/get-fallback-metrics-from-font-file.ts) to analyze the binary, and generates a CSS file referencing your local assets. This approach eliminates external DNS lookups while maintaining the same layout shift protection through computed fallback metrics.

## Configuring Font Display Behavior

While the default `font-display` strategy prioritizes performance, you can customize the rendering behavior to match your user experience requirements.

```typescript
import { Roboto } from 'next/font/google';

const roboto = Roboto({
  weight: ['400'],
  subsets: ['latin'],
  display: 'swap',
});

```

According to [`packages/font/src/constants.ts`](https://github.com/vercel/next.js/blob/main/packages/font/src/constants.ts), the default strategy uses `optional` to prevent invisible text, but you can specify `swap`, `block`, `fallback`, or `optional` depending on your UX requirements. This value maps directly to the generated `@font-face` rule's display property.

## Build-Time Workflow and Performance Benefits

Understanding the exact build process helps explain why `next/font` outperforms manual implementations:

1. **Static Analysis**: During compilation, the loader validates your font configuration through [`validate-google-font-function-call.ts`](https://github.com/vercel/next.js/blob/main/validate-google-font-function-call.ts) or [`validate-local-font-function-call.ts`](https://github.com/vercel/next.js/blob/main/validate-local-font-function-call.ts) and reads font file metadata.

2. **Metric Extraction**: For local fonts, the system parses binary data in [`get-fallback-metrics-from-font-file.ts`](https://github.com/vercel/next.js/blob/main/get-fallback-metrics-from-font-file.ts) to calculate dimensional fallbacks; for Google fonts, it analyzes the CSS response in [`packages/font/src/google/loader.ts`](https://github.com/vercel/next.js/blob/main/packages/font/src/google/loader.ts).

3. **CSS Generation**: A minimal stylesheet containing `@font-face` rules with fallback metrics and display strategies is created and inlined into the page.

4. **Resource Injection**: The framework inserts `<link rel="preload">` tags for the actual font files into the HTML head, ensuring early discovery by the browser.

5. **Runtime Rendering**: The browser paints text immediately using the metric-matched fallback, then seamlessly swaps to the custom font without layout shifts.

This pipeline eliminates the three most common font-related performance issues: invisible text from missing `font-display`, layout shifts from unreserved space, and excessive HTTP requests from multiple weight files.

## Summary

- **Use `next/font`** instead of manual `<link>` tags to automatically handle preloading and fallback generation.
- **Import from `next/font/google`** for Google Fonts or **`next/font/local`** for self-hosted files like `.woff2` assets.
- **Zero CLS** is achieved through build-time metric extraction in [`get-fallback-metrics-from-font-file.ts`](https://github.com/vercel/next.js/blob/main/get-fallback-metrics-from-font-file.ts), which creates dimension-matched fallbacks.
- **Automatic preloading** occurs via [`packages/font/src/google/loader.ts`](https://github.com/vercel/next.js/blob/main/packages/font/src/google/loader.ts) and the local equivalent, ensuring early font discovery.
- **Configurable display** options default to `optional` but support `swap` and other strategies via the `display` parameter.

## Frequently Asked Questions

### Does next/font work with variable fonts?

Yes. The Google font loader in [`packages/font/src/google/loader.ts`](https://github.com/vercel/next.js/blob/main/packages/font/src/google/loader.ts) automatically detects variable font capabilities and constructs single-file URLs that include all specified weights and axes. This reduces network requests compared to loading individual static font files for each weight.

### How does next/font prevent layout shifts without font-display: swap?

The system prevents layout shifts by generating fallback fonts that match the exact dimensions of your custom font. The [`get-fallback-metrics-from-font-file.ts`](https://github.com/vercel/next.js/blob/main/get-fallback-metrics-from-font-file.ts) utility extracts ascent, descent, and size-adjust values at build time, creating a temporary font face that occupies identical space. When the real font loads, it replaces the fallback without changing element dimensions, eliminating CLS even with `font-display: optional`.

### Can I use next/font with CSS-in-JS libraries like styled-components?

Yes. The font loader returns a `className` string that you can apply to any element or global styles. For CSS-in-JS, import the font in your layout file and pass the `className` to your theme provider or global style component. The generated CSS is still injected into the document head automatically.

### What happens if my local font file path is incorrect?

The validation layer in [`validate-local-font-function-call.ts`](https://github.com/vercel/next.js/blob/main/validate-local-font-function-call.ts) throws a `NextFontError` at build time if file paths are invalid or if required metadata (like weight) is missing. This prevents runtime 404 errors and ensures all referenced font assets exist before deployment.