CLI tool
Munter/subfont avatar
Munter/subfont

subfont Webfont Subsetting and Preloading for Static Sites

Command line tool to optimize your webfont loading. Aggressive subsetting based on your font use, self-hosting of Google fonts and preloading

1,636 stars29 forksJavaScriptMIT

At a glance

What is it?
subfont is a JavaScript command line tool that traces font usage in static pages, creates narrower font subsets, and changes preload and fallback behavior. It fits build artifacts and local or Google Fonts, but its URL scraping mode and automatic character tracing impose important boundaries.
Who is it for?
Engineers with static build artifacts, especially sites using local fonts or Google Fonts, should evaluate subfont against a representative deployment output and inspect missing-glyph warnings, subset coverage, preload placement, and fallback behavior before adoption.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 33 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

subfont Targets the Font Delivery Bottleneck in Static Pages

subfont addresses a specific static-site problem: a page may request full font files even though the visible page uses only a small number of characters and font variants. A conventional build often starts with an @font-face rule whose `src` points to a complete local file or a Google Fonts resource. The browser must then download that resource before the relevant text can use the intended face. Subfont changes that arrangement by analyzing the page, finding the characters associated with each font, producing smaller font files, and adding references intended to reach the browser earlier.

The project is aimed at developers who control deployable static output, including people whose HTML is generated by another build system. It is also relevant to teams self-hosting Google Fonts, since the README lists Google Fonts and local fonts as the currently supported font services. Its purpose is narrower than a general-purpose font editor. It does not create typefaces or redesign typography. It changes the font artifacts and loading instructions associated with a traced page so that each deployed @font-face can serve the observed character set.

The README presents the result in terms of payload size and time to first meaningful paint. That claim depends on the page and deployment, so repository contents alone cannot establish a fixed improvement. What the documentation does establish is a concrete transformation: exact subsets, warnings for absent glyphs, new font names, preloading, and asynchronous placement of the original @font-face CSS. Those are the parts an engineer can inspect after producing artifacts.

subfont Traces Pages, Fonts, and Character Usage

The repository identifies Assetgraph as the component used to trace a site's dependency graph, including when writing output to another directory. Subfont combines that graph with font-processing dependencies named in `package.json`, including `font-tracer`, `fontverter`, `font-snapper`, and `harfbuzzjs`. The visible design is therefore static analysis across HTML, CSS, font files, and linked pages, followed by font conversion and HTML or CSS output. Browserlist configuration influences the selected font formats and any associated polyfill selection.

For each discovered @font-face, automatic tracing determines which characters are used. Subfont can warn when requested text has no matching glyph in the selected webfont. It then creates a subset from the characters actually associated with that face. The README says the resulting subsets receive new names and are prepended to the original font family. This arrangement lets the narrower subset handle observed text while preserving the original font as a fallback for characters that were absent from the subset.

Variable fonts receive an additional optimization when `--instance` is used: the variation space is reduced based on actual usage. Format selection normally follows the browsers covered by `--browsers` or the project's Browserslist configuration, although `--formats` can request `woff2`, `woff`, or `truetype`. The `--font-display` option controls the injected descriptor and accepts `auto`, `block`, `swap`, `fallback`, or `optional`, with `swap` as the documented default.

Static analysis cannot observe every string that a later script may create. For that case, `--dynamic` adds tracing in a headless browser with JavaScript enabled. This expands observation beyond static source, but it still does not make every possible runtime state predictable. The fallback mechanism remains a separate protection for dynamically injected content.

Installing subfont and Processing Deployment Artifacts

The README installs the command globally through npm. This form is intended for a machine where the `subfont` executable should be available from a shell.

bash
npm install -g subfont

After installation, the documented starting point is a directory of files ready for static hosting. The following command writes a copy of the traced site to `path/to/outputDir`, where the entry page is passed first and the output directory is selected with `-o`.

bash
subfont path/to/index.html -o path/to/outputDir

The README explicitly advises checking warnings from Assetgraph and confirming that expected files exist in the output directory. A first inspection should therefore cover the HTML, generated font files, rewritten @font-face declarations, preload hints, and any missing-glyph messages.

If another build system already created deployable artifacts and subfont should modify them in place, use `-i` as documented. Because this overwrites the selected HTML files in their current location, the README recommends restricting it to build artifacts rather than authoring sources.

bash
subfont path/to/artifacts/index.html -i

For original files, the documented alternative is to make a recursive working copy and process that copy. That preserves the source tree while still requiring the engineer to verify the generated page and assets. These commands should be treated as a build stage whose output is reviewed, not as a command to run blindly over source-controlled originals.

Glyph Coverage Needs Explicit Review After Automatic Tracing

The largest technical risk is not whether the common characters are subsetted. It is whether a character appears only after the traced page runs. Automatic tracing can miss text introduced through runtime data, user input, locale-dependent content, or routes outside the crawl. A missing glyph warning is useful evidence, but the absence of a warning is not proof that all later states are covered. The README itself gives two controls for coverage, which shows that automatic tracing is expected to have a boundary.

For a specific @font-face, adding `-subfont-text` includes declared characters in that face's subset. The following documented example adds all decimal digits to the bold italic Roboto variant.

css
@font-face {
  font-family: Roboto;
  font-style: italic;
  font-weight: 700;
  src: url(roboto.woff) format('woff');
  -subfont-text: '0123456789';
}

This is the more precise control because it applies to the selected declaration. The `--text` option is broader: the README describes it as additional characters for every @font-face found on the page. It is convenient when a shared set, such as digits, is valid across all generated subsets, but it may unnecessarily enlarge unrelated fonts when only one face needs the characters.

Fallbacks are enabled by default and can be disabled with `--no-fallbacks`. Keeping them helps when runtime content requests a character excluded from the narrow subset. It also means engineers should inspect whether the original font is loaded only after the subset, because disabling fallbacks would remove that stated protection for dynamic content. The appropriate setting depends on whether the original @font-face should be available without conflicting with the optimization.

subfont Output Modes Separate Build Automation from URL Scraping

Subfont offers three distinct operating modes, and they should not be treated as equally production-oriented. In-place processing fits the final files produced by a build. Output-copy processing uses Assetgraph to trace dependencies and write a new directory. URL scraping accepts an HTTP address and writes a local result, but the README warns that it can fail in several ways and calls it mostly a demo feature for a quick look.

The documented URL command is simple:

bash
subfont https://yourpage.me -o path/to/outputDir

That warning matters. Scraping sees whatever the URL returns and whatever references can be traced from it. Authentication, redirects, server-specific rendering, inaccessible assets, or page behavior outside the fetched representation can all affect the result. The README does not define guarantees for those cases, so URL mode should not be presented as equivalent to deterministic integration into a build pipeline.

`--recursive` changes local traversal behavior by following relative and root-relative links while staying inside the input domain. This can be useful for a multi-page static site, but it increases the output surface that must be reviewed. `--inline-css` inlines the generated subset @font-face declarations, while the default keeps them separate. Neither option removes the need to verify the resulting HTML.

A direct alternative is a conventional font pipeline that manually creates glyph subsets and copies the selected files into static assets. That approach requires explicit character lists and more manual synchronization, but it avoids tracing behavior and its runtime-coverage uncertainty. Subfont is more convenient when actual usage is represented in static files. Manual subsetting is easier to reason about when a small, fixed glyph set already satisfies the site.

Maintenance, Compatibility, and MIT Upgrade Considerations

The repository is not archived, and its last push was on 2026-09-20. That supports a judgment of recent repository activity, but the listed release history is less current: it includes v6.0.0 from 2021-04-18, v5.2.1 from 2020-09-01, and v5.2.0 from 2020-08-02. Meanwhile, `package.json` declares version 7.3.0 and Node.js compatibility of `>=10.0.0`. The discrepancy between the visible release list and package version means release expectations should be checked against the changelog and package artifacts used by the deployment, rather than inferred from one field.

The Node.js requirement is unusually old in current runtime planning, while dependencies include packages whose compatible Node.js ranges must resolve during installation. The repository contains a `CHANGELOG.md`, an `npm` package definition, and automated lint and test scripts. Those files provide places to inspect compatibility and upgrade notes. The README does not claim that a current deployment platform still supports Node.js 10 or that every current release has identical setup requirements.

The MIT license permits use, modification, distribution, and sublicensing under its conditions, while preserving the copyright and license notice. License obligations still apply to redistributed copies and derivative distributions. Teams should inspect `LICENSE.md` for the exact notice and preserve it where required. This is not legal advice.

The main operational upgrade cost is verification. Each change can alter generated font families, file names, preload tags, CSS placement, and the interaction between subsets and original fallbacks. A representative static build is therefore more informative than merely confirming that the CLI starts. Check missing-glyph output and compare generated artifacts with the deployment model before accepting an upgrade.

Editorial conclusion

Engineers with static build artifacts, especially sites using local fonts or Google Fonts, should evaluate subfont against a representative deployment output and inspect missing-glyph warnings, subset coverage, preload placement, and fallback behavior before adoption. Projects that depend heavily on runtime-generated text, broad client-side rendering, or font services outside the documented list are poor candidates unless they can establish and verify glyph coverage themselves. The first release decision should follow checking the actual output directory and confirming that generated subsets contain every character a page can display.

Frequently asked questions

Which font sources does subfont support?

The README lists Google Fonts and local fonts as the currently supported font services. It asks users with knowledge of other font services that have liberal font usage licenses to open an issue.

How can I make sure subfont includes characters used at runtime?

The `--dynamic` option traces font usage in a headless browser with JavaScript enabled. Subfont also enables original-font fallbacks by default, and `--text` or the `-subfont-text` declaration property can include explicit characters.

Should subfont modify source files or deployment artifacts?

The README recommends processing files that are ready for static hosting and using `-i` only for build artifacts. For original files, it recommends making a recursive copy and running subfont on that copy.

Can subfont optimize a page through its public URL?

Yes, the CLI accepts URLs and can write results to an output directory. The README describes HTTP scraping as likely to fail in several ways and mostly as a demo feature, so build artifacts are the more dependable input for production processing.

Official sources

  1. Issues
  2. License: MIT
  3. Munter/subfont on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/munter-subfont.svg)](https://hysenlabs.com/projects/munter-subfont)

Was this useful?