Technology · Next.js
Next.js Font Optimization
Load web fonts efficiently with next/font for performance and UX.
TL;DR
- 01Use next/font to load Google Fonts automatically.
- 02Font files are hosted locally for faster loading.
- 03Subset and weight fonts to reduce bundle size.
Google Fonts
- Import and use Google Fonts with next/font.
import { Inter } from "next/font/google"; const inter = Inter({ subsets: ["latin"] }); export default function RootLayout({ children }) { return ( <html className={inter.className}> <body>{children}</body> </html> ); } - Fonts are downloaded at build time and hosted locally.
- No additional network requests for fonts during page loads.
- Automatic font fallback to prevent layout shifts.
Multiple Fonts
- Use multiple Google Fonts in the same project.
import { Inter, Playfair_Display } from "next/font/google"; const inter = Inter({ subsets: ["latin"] }); const playfair = Playfair_Display({ weight: ["400", "700"], subsets: ["latin"] }); export default function Page() { return ( <div> <h1 className={playfair.className}>Title</h1> <p className={inter.className}>Body text</p> </div> ); } - Apply different fonts to different elements.
- Reduce bundle size by specifying only needed weights.
- Use CSS variables to apply fonts globally via Tailwind or CSS.
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" }); export default function RootLayout({ children }) { return <html className={inter.variable}>{children}</html>; } // In CSS: font-family: var(--font-inter); - Export fonts from a shared module to avoid duplicate declarations.
// lib/fonts.ts import { Inter, Roboto_Mono } from "next/font/google"; export const inter = Inter({ subsets: ["latin"] }); export const mono = Roboto_Mono({ subsets: ["latin"] });
Font Weights and Subsets
- Specify weights to load only what you need.
const inter = Inter({ weight: ["400", "500", "700"], subsets: ["latin"] }); - Use subsets to reduce font file size.
const playfair = Playfair_Display({ subsets: ["latin"], // Only Latin characters display: "swap" // Show fallback while loading }); - Display property controls fallback behavior.
const font = Inter({ display: "swap", // Show fallback immediately // "auto" (default), "block", "fallback", "optional" }); - Use adjustFontFallback to reduce cumulative layout shift further.
const inter = Inter({ subsets: ["latin"], adjustFontFallback: true // adjusts metrics of fallback font }); - Load a variable font instead of multiple weights for best performance.
const inter = Inter({ subsets: ["latin"] // Inter is a variable font — no weight array needed });
Custom Fonts
- Load custom fonts from local files.
import localFont from "next/font/local"; const customFont = localFont({ src: [ { path: "../fonts/custom.woff2", weight: "400", style: "normal" }, { path: "../fonts/custom-bold.woff2", weight: "700", style: "normal" } ] }); - Place font files in the public folder.
public/ fonts/ custom.woff2 custom-bold.woff2 - Use the custom font in components.
- Apply a custom font via className on a wrapper element.
export default function RootLayout({ children }) { return ( <html className={customFont.className}> <body>{children}</body> </html> ); } - Use a CSS variable with a local font to integrate with Tailwind.
const customFont = localFont({ src: "../fonts/custom.woff2", variable: "--font-custom" }); // tailwind.config: fontFamily: { brand: ["var(--font-custom)"] }
Performance Best Practices
- Use font display swap to prevent layout shift.
const inter = Inter({ display: "swap", // Shows fallback font immediately subsets: ["latin"] }); - Load fonts early in the layout for best results.
// app/layout.tsx (root layout) import { Inter } from "next/font/google"; const inter = Inter(); export default function RootLayout({ children }) { return <html className={inter.className}>{children}</html>; } - Subset fonts to languages you support.
const inter = Inter({ subsets: ["latin", "latin-ext"] // Add extended Latin }); - Measure font impact on Core Web Vitals using web-vitals.
import { getCLS } from "web-vitals"; getCLS(console.log); // CLS score should be near 0 with font optimization - Use preload: false to skip preloading a font that is not above the fold.
const mono = Roboto_Mono({ subsets: ["latin"], preload: false // Only loaded when used, not preloaded });
Tip: Use next/font to load Google Fonts — it handles optimization automatically and improves Core Web Vitals.
Warning: Don't load too many font weights or families — each adds overhead. Stick to 2–3 fonts with a few weights each.