Load and optimize fonts in Next.js
1. Install Fonts
Download open source fonts from
- Google Fonts
- others
2. Optimize Font
Usually the fonts downloaded comes in the format .ttf
. They are high quality but files are larger. Not intended for web use.
The recommeded is .woof2
as the primary format and .woof
as fallback.
To optimize them need to convert .ttf
to .woff2
format and for that we will use:
3. Import Font
src/fonts/gluten.ts
import localFont from "next/font/local"
export const gluten = localFont({
src: [
{ path: "./Gluten-Thin.woff2", weight: "100", style: "normal" },
{ path: "./Gluten-ExtraLight.woff2", weight: "200", style: "normal" },
{ path: "./Gluten-Light.woff2", weight: "300", style: "normal" },
{ path: "./Gluten-Regular.woff2", weight: "400", style: "normal" },
{ path: "./Gluten-Medium.woff2", weight: "500", style: "normal" },
{ path: "./Gluten-SemiBold.woff2", weight: "600", style: "normal" },
{ path: "./Gluten-Bold.woff2", weight: "700", style: "normal" },
{ path: "./Gluten-ExtraBold.woff2", weight: "800", style: "normal" },
{ path: "./Gluten-Black.woff2", weight: "900", style: "normal" }
],
variable: "--font-gluten", // used with CSS variables
display: "swap"
})
If want to import manually in the header element:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Gluten&display=swap&subset=latin" as="font" type="font/woff2" crossorigin>
<!-- or if importing locally -->
<link rel="preload" href="/fonts/roboto-regular.woff2" as="font" type="font/woff2" crossorigin>
Things to consider:
- Dont forget to add subset to reduce file size
- Add
preconnect
- Host font locally
- Use 2–3 weights max (e.g., 400, 500, 700).
- Use "variable font" (a single font that contains multiple weights) instead of "static font" (multiple files of different font weights)
4. Apply Font
Apply directly
- Quickly and simpler
- Sets by default font to the element and its children unless it's overrided.
- Use case: use for certain components
<html lang="en" className={`... ${gluten.className}`}>
Apply using CSS variables with TailwindCSS
- Requires more setup
- Font as a tailwind variable
Assuming Tailwindcss v4 installed
src/app/global.css
@theme inline {
...
--font-primary: var(--font-gluten);
...
}
Then, also add
src/app/layout.tsx
<html lang="en">
<body className={cn("font-primary", gluten.variable)}>
{children}
</body>
</html>
Now you can use font-primary
in any component or html element.
Under the hood, adding gluten.variable
will:
- add in the body element: --font-gluten: "gluten"
- generate css code with
@font-face{}
for every font-weight.
@font-face {
font-family: 'gluten';
src: url('@vercel/turbopack-next/internal/font/local/font?{%22path%22:%22./Gluten-Thin.woff2%22,%22preload%22:true,%22has_size_adjust%22:true}') format('woff2');
font-display: swap;
font-weight: 100;
font-style: normal;
}
...
@font-face {
font-family: 'gluten Fallback';
src: local("Arial");
ascent-override: 55.81%;
descent-override: 20.55%;
line-gap-override: 0.00%;
size-adjust: 115.56%;
}
.className { font-family: 'gluten', 'gluten Fallback'; }
.variable { --font-gluten: 'gluten', 'gluten Fallback'; }