Skip to main content
All Docs
FeaturesBlockManOSUpdated March 26, 2026

Blog: Font Optimisation with next/font (PERF-03)

Font Optimisation with next/font (PERF-03)

Version: 1.0.58
Category: Performance — Frontend

Background

Until v1.0.58, the root layout of the application declared its font stack via a plain HTML inline style:

// Before — src/app/layout.tsx
<body style={{ fontFamily: 'Geist, Inter, system-ui, sans-serif' }}>
  {children}
</body>

This works, but it leaves several Next.js font optimisation capabilities unused:

CapabilityInline stylenext/font
font-display: swap❌ Manual✅ Automatic
Subsetting❌ None✅ Automatic
Self-hosting❌ None✅ Automatic
Zero layout shift❌ Not guaranteed✅ Built-in

In addition, globals.css referenced two CSS variables — --font-geist-sans and --font-geist-mono — that were not explicitly defined within the application bundle. These variables were only available if the host shell package happened to inject them, creating a fragile dependency.

What Changed

The inline style declaration has been replaced with next/font in src/app/layout.tsx. The Geist font family is loaded via the geist package and applied through a className on the <body> element, which is the pattern recommended by the Next.js documentation.

// After — src/app/layout.tsx
import { GeistSans } from 'geist/font/sans';
import { GeistMono } from 'geist/font/mono';

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

The CSS variables --font-geist-sans and --font-geist-mono are now reliably defined by next/font at build time and are available throughout globals.css without depending on an external shell package.

Why This Matters

Eliminated layout shift risk

next/font injects font-display: swap automatically. This means text is immediately rendered in a fallback system font while the custom font loads, preventing invisible text (FOIT) and reducing Cumulative Layout Shift (CLS) — a Core Web Vital that affects both user experience and search ranking.

Reliable CSS variable definitions

Previously, any component in globals.css that referenced var(--font-geist-sans) or var(--font-geist-mono) could silently fall back to a browser default if the shell package was absent or updated. The variables are now owned and emitted directly by the application.

Self-hosting readiness

If additional fonts are introduced in the future, next/font/google or next/font/local will automatically download and self-host them at build time, removing runtime dependencies on third-party font CDNs and improving both performance and privacy compliance.

Impact

  • End users: Faster perceived text rendering and reduced risk of layout shift on initial page load.
  • Developers: Font configuration is now co-located in src/app/layout.tsx and version-controlled; no implicit dependency on a shell package for CSS variables.
  • No breaking changes: No API, data model, or user-facing feature changes were made in this release.