Library / SDK
googlefonts/fontations avatar
googlefonts/fontations

Fontations: Rust crates for reading and rewriting OpenType font files

Reading and writing font files

847 stars83 forksRustApache-2.0

At a glance

What is it?
Fontations is a workspace of Rust crates for parsing, inspecting and modifying OpenType fonts, built to replace FreeType in Google applications with something memory safe. read-fonts parses without allocating, write-fonts owns the tables and can write them back out, and skrifa is the mid level layer most consumers will use.
Who is it for?
Fontations suits a Rust team that needs to read, subset or rewrite OpenType fonts with predictable memory behaviour, and the crate split lets you depend on read-fonts alone when parsing is all you need. It does not suit a project that needs a stable published release, because the only tag is v0.0.5 from 2023 while the last push was on 2026-10-20, so the version numbers in the registry are not a reliable guide to the current state of the code.
Can I use it commercially?
Yes. Apache-2.0 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 received new commits within the last day.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

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

Editorial analysis

Four crates split the job of reading and writing font files

Fontations is a repository of foundational crates for reading and manipulating OpenType font files. The stated motivation is a desire for more dependable and performant open tools for font engineering and production tasks, and the README points to the oxidize project for the wider argument.

The four main library crates divide the work cleanly.

font-types holds the common definitions of the core types used in the OpenType specification. The README calls it a small crate and says it is intended as a basic dependency for any project reading or manipulating font data.

read-fonts parses and accesses font files, and is described as a high performance parser suitable for shaping. The performance claim is specific and checkable: it performs no allocation and no copying.

write-fonts modifies and writes font data. It contains owned types representing the various tables and records in the specification, plus code for compiling those and writing out font files. It has an optional dependency on read-fonts, and with that dependency it can also parse font data, which can then be modified and written back out to disk. That optional coupling is the key to the whole design: read, mutate, write, with one type system.

skrifa is the mid level library giving access to metadata inside a font and support for loading glyph outlines. Its primary purpose is stated as replacing FreeType in Google applications, with a link to the Chrome developer blog post on memory safety and fonts. It is also used for tasks such as producing assets for the Google Fonts icons product.

The audience is Rust developers working on font pipelines, text shaping stacks and asset generation, not web designers looking for a font.

The crate graph shows the layering, and which projects are built on top

The README carries a mermaid dependency map of the font related crates, and it is the clearest statement of the architecture. The map is described as non-dev dependencies among the font related crates, and it notes that fontc primarily uses the fontations crates via write-fonts and skrifa.

The layering is strict and one-directional. font-types sits at the bottom with no dependencies of its own in the graph, read-fonts depends on font-types, and write-fonts depends on both font-types and read-fonts. skrifa depends on read-fonts, which is what makes it the convenience layer above the parser.

The edges from the map read like this.

mermaid
    read-fonts --> font-types
    skrifa --> read-fonts
    write-fonts --> font-types
    write-fonts --> read-fonts
    write-fonts --> kurbo
    skera --> skrifa
    skera --> write-fonts

kurbo comes from the linebender project and is the 2d curves library, which is how write-fonts handles outlines. The map also shows crates outside the four headline libraries. fauntlet compares skrifa and freetype, which is a differential testing tool, and it depends on freetype-rs, the bindings for the FreeType library. norad handles Unified Font Object files and depends on kurbo.

Two crates in the graph are worth attention because they are newer directions rather than parsing basics. skera is described as subsetting, creating font subsets, and it depends on both skrifa and write-fonts, so subsetting is built as a consumer of the read and write layers. incremental-font-transfer is the client side IFT patch application, and it depends on font-types, read-fonts, skrifa, write-fonts and skera, so it is the top of the stack and touches everything.

The graph comment says it is up to date as of June 2026 and can be updated by inspecting all the Cargo.toml files, which is a useful signal about how seriously the map is maintained.

Much of the parser and writer is generated by a code generator crate

A detail that changes how you read the source: much of the code in the read-fonts and write-fonts crates is generated automatically. Generation is performed by the font-codegen crate.

The README points to a codegen tour for an overview of what is generated and how it works, and to the font-codegen readme for an overview of how to use the font-codegen crate itself.

This is a design with a clear rationale and a clear cost. On the rationale side, the OpenType specification is large and mechanical, and hand-writing owned types for every table and record is a large amount of code that has to be kept in step with the spec. Generating it from a machine readable description of the spec keeps the two in step. On the cost side, the generated code is not the place to look for the intent of the crate, and a change to the generator is a change to two crates at once.

The workspace membership shows how much is generated infrastructure rather than library code. Alongside the four headline crates, the members list font-codegen, font-test-data, fauntlet, skera, fuzz, shared-brotli-patch-decoder and incremental-font-transfer.

shared-brotli-patch-decoder is worth a note because it explains the incremental font transfer story. A patch format that reduces a font to a delta needs to decompress that delta, and doing it with a pure Rust Brotli decoder avoids a C dependency in a stack that exists precisely to avoid C dependencies.

The dependency pinning in the workspace manifest is unusually conservative, and the comments explain why: bytemuck, yoke and smallvec are pinned to versions that must be available in all deployment environments, specifically the floor of the versions supported by google3, Chrome and Android, with links to the corresponding version files in each tree. For a workspace that ships inside Chrome and Android, that constraint is not negotiable, and it is why the pinned bytemuck version is 1.14.0 rather than the latest.

Fuzzing is part of the workflow, not an afterthought

Font parsers read hostile input by definition, so the project invests in fuzzing infrastructure. The repository carries a Fuzzing Status badge from the oss-fuzz build logs, and the README explains how to use it.

The fuzzers live in the fuzz/ crate in the repository and are implemented with the cargo-fuzz crate. The oss-fuzz configuration lives in the oss-fuzz repository under projects/fontations, and the build.sh there looks for the built fuzz binaries at target/x86_64-unknown-linux-gnu/release/fuzz_*.

Two design notes explain why this integrates well. The configuration is designed so additional fuzzers can be added to fontations without touching oss-fuzz every time, and the same build.sh also controls the test corpus, so the git clone lines that fetch the corpus live in one place.

The reproduction procedure is documented for reporters, which is a sign of a project that expects crash reports from outside.

sh
cargo +nightly  fuzz build -O --debug-assertions
sh
target/x86_64-unknown-linux-gnu/release/fuzz_skrifa_outline ~/Downloads/clusterfuzz-testcase-minimized-fuzz_skrifa_outline-6213391169945600

The first command builds the fuzzers and the second passes a specific minimised test case to one of them, the skrifa outline fuzzer in this example. Coverage can be viewed on oss-fuzz by searching for the project name.

Performance is checked against an existing yardstick rather than invented internally. The README points at the harfbuzz performance documentation, which contains instructions for running the harfbuzz benchmarks including against Fontations.

Contributing and releasing are scripted, with a version bump script

The contributor workflow is small and mostly mechanical, which suits a project with a lot of generated code.

Git hooks are included in the repository under resources/githooks, and they are optional. To have them run automatically on commit and push, you point the repository at them as the hooks path.

sh
git config core.hooksPath "./resources/githooks"

There is a note for macOS users, because the hooks assume GNU coreutils and the documentation says to install them via `brew install coreutils`.

Releasing is guided by cargo-release, which the README says can be installed with cargo install cargo-release, and you may need pkg-config installed for it to work.

The release process has three steps. First, run cargo release changes to see which crates have been modified since their last release. Second, decide the new versions, with an explicit rule about how the numbers move: before 1.0, breaking changes bump the minor version number and non-breaking changes modify the patch number. Third, update the manifest versions and release, with a script in resources/scripts that orchestrates the process because cargo release does the heavy lifting.

shell
# To see usage
./resources/scripts/bump-version.sh
# To do the thing
./resources/scripts/bump-version.sh read-fonts write-font

The example invocation names the crates to bump, read-fonts and write-font, which is the per crate part of a workspace release.

The version rule deserves attention from anyone depending on these crates. A 0.x crate where breaking changes bump the minor version is the pre-1.0 convention, and it means the minor number is effectively the compatibility boundary. The only tagged release listed for the repository is v0.0.5 from 2023-01-05, which tells you the published version numbers have not kept pace with the activity in the repository.

Where Fontations is the wrong tool

The first wrong-tool case is a project that needs a stable published release to pin against. The only release tag is v0.0.5 from January 2023, while the last push to the repository was on 2026-10-20. Whatever is in the repository today is the work, and there is no versioned artefact to match it to. For a team that vendors dependencies and wants a known good commit per release, that is friction rather than a detail.

The second case is a project that is not writing Rust. These are Rust crates, and while the OpenType format is language neutral, the implementation is not portable. A team working in C++ with an existing shaping stack is not going to adopt these crates, and the FreeType comparison tooling in the repository, fauntlet, exists precisely because FreeType remains in the picture elsewhere.

The third case is a task that the crates do not cover. Fontations is about reading and writing font files. It is not a layout engine, it does not shape text, and it does not do rasterisation. skrifa loads glyph outlines, and kurbo, the 2d curves library from linebender, handles the geometry, but converting outlines to pixels is a different problem with different tools.

There is also a constraint worth knowing about the workspace as a whole. The pinned dependency floors for bytemuck, yoke and smallvec are set by the version of those crates available in Chrome and Android, which means the workspace deliberately does not take the latest versions of its own dependencies. If your project needs a newer smallvec than Chrome can take, you will be resolving a conflict that Fontations does not create but also does not help with.

On licensing, the workspace manifest states MIT OR Apache-2.0, and the repository carries both LICENSE-APACHE and LICENSE-MIT files, so you can take either. That dual licensing is the conventional Rust choice and carries no copyleft obligation.

Editorial conclusion

Fontations suits a Rust team that needs to read, subset or rewrite OpenType fonts with predictable memory behaviour, and the crate split lets you depend on read-fonts alone when parsing is all you need. It does not suit a project that needs a stable published release, because the only tag is v0.0.5 from 2023 while the last push was on 2026-10-20, so the version numbers in the registry are not a reliable guide to the current state of the code. Before adopting, check whether your platform's Rust version meets the workspace minimum of 1.85, and read the font-codegen readme if you plan to rely on the generated code, because much of read-fonts and write-fonts is produced by it.

Frequently asked questions

What is Fontations used for?

Fontations is a workspace of Rust crates for reading and manipulating OpenType font files, built with the goal of providing more robust and performant open tooling for font engineering and production tasks. skrifa, the mid level library, is intended to replace FreeType in Google applications.

Which crates make up Fontations?

The four main library crates are font-types for the core OpenType types, read-fonts for parsing and access, write-fonts for modifying and writing font data, and skrifa as the mid level library for metadata and glyph outlines. The workspace also contains font-codegen, font-test-data, fauntlet, skera, fuzz, shared-brotli-patch-decoder and incremental-font-transfer.

Does read-fonts allocate memory while parsing fonts?

The documentation states that read-fonts is a high performance parser suitable for shaping and that it performs no allocation and no copying. write-fonts has an optional dependency on read-fonts so that parsed data can be modified and written back out to disk.

How do I reproduce a fuzzing crash in Fontations?

Build the fuzzers with cargo +nightly fuzz build -O --debug-assertions, then pass the downloaded testcase to the relevant binary under target/x86_64-unknown-linux-gnu/release/. The README notes that the oss-fuzz build.sh also controls the test corpus, with the git clone lines for it.

What license is Fontations released under?

The workspace manifest states MIT OR Apache-2.0, and the repository contains both LICENSE-APACHE and LICENSE-MIT. The workspace also requires Rust 1.85 or newer.

Official sources

  1. googlefonts/fontations on GitHub
  2. Issues
  3. License: Apache-2.0
  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/googlefonts-fontations.svg)](https://hysenlabs.com/projects/googlefonts-fontations)