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:
| Capability | Inline style | next/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.tsxand 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.