Skip to content
posts

769 megabytes of fonts

How a one-line mistake put most of a gigabyte in a static site, and what the fix actually costs.

I rebuilt this site recently. Before deleting the old one I looked at what was in it, which is how I found this:

769M	public/fonts

One hundred and two TrueType files. The full Fira Code Nerd Font family in three cuts — NerdFont, NerdFontMono, NerdFontPropo — and all of Iosevka besides. Eighty megabytes of it packed into git history, cloned by anyone who ever touched the repository.

How it happens

Not through carelessness, exactly. It happens because “add the font” really is one command. You download the release, unzip it into public/, reference one family in your CSS, and the site works. Nothing warns you. The build does not slow down enough to notice. The deploy succeeds.

And the failure is invisible from the outside, because a browser only downloads the files a stylesheet actually asks for. The waste is real but it is all on the repository, the CI cache, and the deploy — not on the visitor. So nothing ever forces the issue.

What is actually in a Nerd Font

The patched fonts are large for a good reason: they carry thousands of icon glyphs in the Unicode private use area, so your prompt can show a git branch symbol. For a terminal that is the whole point. For a website it is almost entirely dead weight.

I measured the difference on one weight of Fantasque Sans Mono:

subset size as woff2
Latin + punctuation 31 KB
the above, plus box drawing, blocks, geometric shapes, braille 38 KB
the above, plus the full icon private use area 1,025 KB

The icons are 96% of the file.

The ranges that matter

Dropping the private use area is easy. The interesting question is what a terminal emulator actually needs beyond Latin, and the answer is more than you would guess:

  • Box drawing (U+2500-257F) and block elements (U+2580-259F) — every border, table, and progress bar a TUI draws.
  • Geometric shapes (U+25A0-25FF) and dingbats — status markers, .
  • Braille (U+2800-28FF) — this is the one that surprised me. Bubble Tea’s default spinners are braille patterns. Omit the range and everything looks fine until something starts loading, at which point you get a row of tofu boxes that vanish before you can screenshot them.

Four weights covering all of that, as woff2: 164 KB total. Against 769 MB, and against roughly 10 MB even if you had been sensible and shipped four unpatched TTFs.

The part worth keeping

I put the subsetting in a script with the ranges commented, and ended it with this:

LIMIT=$((400 * 1024))
if [ "$total" -gt "$LIMIT" ]; then
    echo "[fonts] ERROR: $total B exceeds the ${LIMIT} B budget" >&2
    exit 1
fi

A comment explaining why the private use area is excluded would not have stopped me the first time, because I never read a comment in a file I did not know existed. A build that fails is harder to walk past.