On this page

Writing

Migrating to Astro 6's Fonts API

Before

Inter loaded from Google’s CDN via a CSS @import, plus hand-written @font-face blocks for a couple of other weights, plus a hand-tuned fallback font to limit before the real font loaded. The @import is a to a third-party server before the page can paint, and it sends every visitor’s IP to Google.

Config

Astro 6’s Fonts API replaces all of that with one array in astro.config.ts:

import { defineConfig, fontProviders } from 'astro/config';

export default defineConfig({
  fonts: [
    {
      provider: fontProviders.google(),
      name: 'Inter',
      cssVariable: '--font-inter',
      weights: [400, 500, 600, 700],
      styles: ['normal'],
      fallbacks: ['sans-serif'],
    },
  ],
});
<Font cssVariable="--font-inter" preload />

fontProviders.google() names where the font comes from during the build only. Astro downloads it once at build time, generates the fallback, hashes the file, and outputs it as a static asset served from your own domain, same as any other file in dist/. No request to Google at page load.

Why this matters

Everything needed to render a page already sits on disk after a static build. The old @import broke that: the page could go down because fonts.googleapis.com was down, not because of anything in this repo. Fetching at build time removes that dependency.

Dropping the hand-tuned fallbacks and switching to build-time downloads took font payload on this site from ~280KB to ~126KB.

What broke on the upgrade

Astro 6 ships on . Two things broke that had nothing to do with fonts directly:

  • @tailwindcss/vite stopped resolving CSS correctly under rolldown-vite. Fix: run Tailwind through PostCSS instead (postcss.config.mjs + @tailwindcss/postcss).
  • @fontsource woff2 files stopped being emitted. A font on a @fontsource-variable import silently dropped its files from the build: no build error, just a 404 in production. Fix: move it into the Fonts API via the fontsource provider instead, which fetches and emits its own files rather than depending on the npm package’s output.

Adding a new font later

Updated 08 July 2026: two more gotchas, both silent (no build error, fonts just fall back to system defaults):

  • A config entry alone emits nothing. The @font-face only lands on a page once a <Font cssVariable="--font-x" /> actually renders somewhere, same as the preload tags in Layout.astro.
  • A font token needs a matching Tailwind utility class to survive inside @theme {}. A token only ever used as var(--font-x), never as a class, gets dropped from the compiled CSS.

The way to catch either: check the built page’s actual @font-face rules, not just the config.

Closing thoughts

The upgrade took about an hour, most of it spent on the two rolldown-vite bugs, not the fonts. Nine @font-face blocks and a hand-tuned fallback are gone, replaced by one array, and the site no longer depends on Google’s servers.

Resources