Google Fonts

Onboarder workflow guide

🐝 Google Fonts has become too big to be maintained as a simple community repository. The platform is now an API distributing and serving more than a thousand font families, and GF has started to see itself as a proper open-source foundry. This means several things:
  1. While in the past spontaneous contributions were still possible, today, the specifics of the requirements and the security in place have made it complicated for a random user to make such a contribution. If a user makes a PR, it will definitely draw some attention, but the PR often needs to be redone by a team member. So, while contribution to the repo is not, in theory, exclusive to the “onboarders” (contracted team members), it tends to be in practice.
  2. Google Fonts has commissioned hundreds of fonts from professional type designers. To onboard these projects (from the moment the font family is considered “ready”), we need a toolchain that automates most of the repetitive tasks such as packaging the fonts (gftools packager) and generating QA proofs (gftools qa).
  3. The workflow must leave no place to doubt about the status of the project. Indeed, once merged into the google/fonts repo, the font still travels through different servers before appearing on the API. It has often happened that fonts never got into production — because they have been forgotten in the sandbox server or elsewhere.
The workflow described below was designed to ensure no lost products during the validation process, to facilitate the latter, and to keep people updated about the status of different projects. It requires active maintenance and regular updates from team members.
It also seemed important to keep the whole status of the repository in one place, mostly to avoid copy-pasting PR links all the time. Therefore, a complete Github-based workflow was chosen, making extensive use of the issue tracker, the milestones feature, the project boards, and the continuous integration system.
This guide will help team members understand the validation process of a font family and the actions required from them to help that process. is a page updated weekly that reports on activity in the google/fonts repo.
Background reading:
nerd  google/fonts repository explained
nerd  Making a PR to Google Fonts

Table of contents

The onboarding process

To preserve the synchronization of source files, the google/fonts repository doesn’t host font sources —only font binaries.

Screenshot of an issue from google/fonts issue tracker.

“Upstream” is the further we can go to the original files; since google/fonts is only hosting a copy of the font files —pulled from that original designer’s repository— we can say that google/fonts is somewhere down the stream. The API processes that file and serves a subsetted version, but the original font file can be found in the downloadable zip file from the platform.

None of these three instances are directly linked, though. At least three persons, at each instance, will interact with that font file before it is available on Let’s go briefly through the process step by step:

  1. After a font has been commissioned or submitted to Google Fonts through the google/fonts issue tracker. An onboarder will be assigned to that project.
  2. The fonts will be reviewed, corrected, and built in the upstream repository. They will then be packaged and sent through a Pull Request (PR) to the google/fonts repository.
  3. From there, another onboarder should QA the font and the overall package before merging it into the google/fonts repository.
  4. An on-call engineer must push the font file to the API.

The font doesn’t go directly to the live API; it has to travel through intermediate servers, where it will be reviewed and validated again to ensure the API is showing the font correctly.

Graphic showing the onboarding process from the issue in google/fonts repository, to a public release on

This graphic shows how a project travels from the google/fonts GitHub repository to

This process takes 2 to 4 weeks, because the push to sandbox or production only happens in alternance once a week — if not less.

You see the importance of the issues and the pull requests (PR) in the graphic. We try to keep connected the issue and the PR that fixes it, but we do track them on different boards. The Google Fonts board tracks the issues (that are our link to the upstream repos), and the Traffic Jam board tracks the PRs (that are our link to the servers and the API).

Finally, it is important to note that while the API is the primary space for the users, the google/fonts repo is the primary space of the onboarders, and the upstream font repo is the primary space of the author. Since it is impossible to satisfy everyone in all spaces, these priorities are to be taken seriously into consideration when facing a problem:

The Google Fonts project board

The project board is a way to sort all the font project issues that are contained in it. There is usually no pull request in this project board (they are tracked in the Traffic Jam board). Each tab has specific filters to be able to focus on one aspect of the issue.

The milestones

Each issue that we intend to care for should be added to the Google Fonts project board, but also to a milestone. This allows us to divide and anticipate the workload in time.

How the Milestone tab looks into the Google Fonts project board.

To preserve a clean workflow, the Milestone needs to be assessed at the end of the quarter so we can move the still-open issues to the next Milestone to be able to close this one.

To have a proper overview of the milestones, the Milestones tab in the GF board allows to see all open issues (triaged by quarter). We can see all the necessary information linked to an issue: the onboarder assigned, the priority level, the progress status, and the labels.

When clicking on a issue, a window opened with more details about that issue

The open issues

Issues in the google/fonts repository are used to define the Google Fonts production pipeline for team members, collaborating designers, and for users to report bugs or suggest new submission ideas.

For the project manager and the onboarder, the bridge between what happens upstream and what is reported downstream is made through the issues. In order to track the project appropriately, the issue must contain a certain number of information, and for that, we use the GitHub API extensively.

What do you see when looking into an issue from google/fonts issue tracker.

One issue per font project

What do we mean by font project? “Adding a new family”, and “upgrading a family” are font projects. We consider the project completed once that version of the font hits production. Upgrading a font after its release on would be considered as a new project and therefore a new issue for it is required.

Issues can be used to communicate with the designer and should be updated regularly with a comment about the progress status. It is recommended to use the template issues in order to have all the information we need to start a project.

We want one issue per font project because we allow a PR to change one font directory only. Therefore, the issue can be closed by the PR that makes these changes. As we say above, it doesn’t mean that the project is completed, though. It happens that we see a problem in sandbox; in this case, we re-open the issue to fix it with another PR. Therefore several PRs can be linked to the same issue.

Several linked PRs for one issue


  1. All issues should be labeled at least with a primary category label (start with I). These labels are grey and inform about the type of project, typically: I New font, I Font upgrade, I Font bug.

  2. The secondary category labels (start with II) are green and allow to add mandatory additional information.

    Every new fonts issues should be labelled with a light-green label:

    • II Commissioned: any project Google financed partly or fully.
    • II Submitted or II Accepted. Commissioned projects have priority over accepted submitted projects.

    When the primary language supported is a complex script (usually not Latin-Cyrillic-Greek), a dark-green label must inform us about it. Indeed, the world languages need special care for the API to display the script appropriately, they also need onboarders with expertise to take care of them. We divided them into script categories:

    • II African
    • II Arabic / Hebrew / Semitic / RTL
    • II CJK
    • II Indic / Brahmic / Thai / Tai

    We also use dark-green labels to precise certain conditions/technologies that require special attention such as:

    • II Color font
    • II Custom axes
    • II Icon / symbols / not text
  3. The teritary category labels (start with III) are orange and allow to know more about the type of upgrade. Every Font upgrade issue should have an orange label:

    • III Expand glyphset
    • III Expand styles
    • III Improve rendering / layout
    • III VF Replacement
  4. When in doubt, call on someone else with these blue labels:

    • -- Needs manager's opinion: This is to apply when Chris and/or Dave are the only ones to make a decision about the issue. It is better to list these in the “Pipeline meeting” doc to be sure they don’t remain unnoticed.
    • -- Needs Eng team opinion: typically issues/bug related to the API. Better to list these in the “technical pipeline meeting” doc to be sure they don’t remain unnoticed.
    • -- Needs expertise: for example, if the primary script is a complex script, applying this label allows us to know that an expert in this script should be assigned to review this issue.

Progress status

The progress status exists through the Project Board. Like the Priorities, they are not labels but a proper custom field displayed as a column in the project boards. It is possible to add more custom fields (and also modify them) in one project board’s settings.

Where to find these custom fields

Manual status:

Automatic status:

The progress status from In progress to PR GF is set manually by the onboarder managing that project. The ones from In Dev to Live should be automated thanks to gftools push module (see below for more information).

This is how to set the progress status manually:

Progress status from an issue

Progress status from teh milestone tab

Progress status from the onboarder's tab

Mandatory content

The closed issues

The Closed Issues tab in the Google Fonts project board.

The Closed issues tab allows to follow the status of each project once they have been merged and send to the dev-sandbox. Their status are: In Dev, In Sanbox or Live. If an issue occurs before it gets live, then the issue should be re-open and amended with a new PR.

Submissions to review

The Submissions to review tab in the Google Fonts project board.

The Submissions to review tab is filtered by the submission label. The submission issues are typically divided into two milestones: the “submission to review” and the “icebox” milestones.

When an issue is placed in the “icebox” milestone, it is the responsibility of the manager to close this issue “as not planned” or keep it open indefinitely.

Answering an issue

Maintaining the repository means answering issues opened by users. Most of them are submissions to review or font bugs. Anything related to te API that seems important should be transferred to the on-call team through the dedicated group chat.

This is how we proceed once a new font is proposed through the issue tracker:

If the submission is not worth reviewing

The Submissions to review tab in the Google Fonts project board.

If the font is worth reviewing but some elements are missing

Such as sources, description in the, etc., we simply ask the designer to provide those elements so we can review the font properly.

If the font is worth reviewing and not missing element

An onboarder should be assigned to give a review. That review is then submitted at the “Pipeline meeting” to a collective vote. The final answer should be given in comment of the submission issue.

Labels for submissions or commissioned projects

Some labels have been created to quickly see what’s blocking the issue, they are red and starts with --:

When to close an issue

Keeping issues unecessarily opened have several impacts:

We can therefore consider that leaving issues unecessarily opened is a proper mistreatment of the users, the team members and the pipeline.

So when to close an issue?

Onboarders’ tabs

The Onboarders tabs are the special project management spaces for each onboarder individually. They can see what is assigned to them, and update the status of each issue by dragging and dropping the issue from a column to another. They are also asked to update regularly the status of project in comment of the related issue.

Example of an individual onboarder's tab

The Traffic Jam project board

The traffic Jam project board is the space where we track, sort and filter the Pull Requests. We use it to check in which server and in which push list a certain version of the family stands.

The first tab would group the PRs by Servers and sort them by Lists. It is particularly useful at the moment of preparing/generating the push lists. You can see everything that is in the dev-sandbox and decide to block and add to a list.

The second tab would group the PRs by Lists and sort them by Labels. It is particularly useful at the moment of checking the fonts in the servers. You can see everything that belonged to a list by type of project and decide to block or to upgrade list.

The status column is updated thanks to the gftools push module. It checks the servers against the font families and output which server displays which version. The lists column on the other hand is updated manually.

  1. In Dev / no list tag: these PRs were merged recently and not added to a list yet. You can add them the tag to_sandbox at the moment of preparing the lists, or blocked if something is wrong after merging.
  2. In Devto_sanbox: the font has not yet been pushed to Sandbox.
  3. In Sandboxto_sandbox: the font directory path has been effectively pushed to Sandbox.
    • Check each item in Sandbox (see later section to know how to check them).
    • If they pass, they can be added into the to_production list.
    • You can also check the item on the list that have not been pushed and investigate why.
    • If a PR had the label small fix it can mean that it is amending a blocked PR in Sanbox. We only need to track one PR per server, if two PRs for the same project are in the same server you can remove one from the project board (usually the one that amends the original one, or the one that contains the less files).
    • Check and update status and list of items that are not covered by the script (knowledge, language, etc)
  4. In Sandboxto_production, it has not been pushed to prod yet.
  5. Liveto_production: it has been effectively pushed to prod. You can remove the list tag if nothing curious or abnormal occurs (such as something you know can’t be live).
  6. whatever / blocked: something is wrong and the PR should be amended to be able to get on a list. A comment should be written in the PR or the linked issue, and the issue re-open. The list of blocked project should be assessed regularly with a will of unblocking them.

The Pull Request

Every new PRs will be automatically added to the Traffic Jam board, except for the ones with the label Tool/Workflow/Repo.

Title and Comment section

Font files should always be packaged with Packager. The first comment and the title are generated by the tool and it ensures the font has been packaged by the Packager and not manually.

Additional information can be added in the comment or the next to help the review. For example if something is expected to appear in the diff, it can spare time to the reviewer to know about it in advance. Eg:


Like issues, the PR must have labels to help understand the project and communicate within the team. These labels should be set by the onboarder onboarding the font.

  1. All PRs should be labelled at least with a primary category label (startwith I). These labels are grey and inform about the type of project, typically:

    • I New font: this family has never been released before, therefore we will be careful of the quality of the design and the aspect of the font that can’t be changed later such as the vertical metrics and the weight distribution etc.
    • I Font upgrade: this family has been released in the past, therefore we will be particularly careful about potential regressions.
    • I Small fix: this is not an outstanding upgrade, it fixes a bug, we don’t need to communicate about it on social media. Or amends a previous one that was merged but didn’t hit production.
    • I Description/Metadata/OFL: doesn’t modify a font file but one or several other files from a font directory.
    • I Designer: concerns the designer directory.
    • I Knowledge: concerns the Knowledge platform.
    • I Lang: pull changes from the subtree repo googlefonts/languages
    • I Axis Registry: pull changes from the substree repo googlefonts/axisregistry.
    • I Tools/workflow/repo: only affects the repository, it should not be tracked in Traffic Jam and its content should not be pushed to a server. For example, the PRs updating the push lists should be tagged with this label so it doesn’t pollute the board.
  2. The secondary category labels (start with II) are dark green and allow to add mandatory additional informations.

    When the primary language supported is a complex script (usually not Latin-Cyrillic-Greek), a dark-green label must inform us about it. This way the person checking the font in sandbox can make sure Latin is not displayed, but the actual primary script of the font:

    • II African
    • II Arabic / Hebrew / Semitic / RTL
    • II CJK
    • II Indic / Brahmic / Thai / Tai

    We also use a dark-green labels to precise certain conditions/technologies that requires special attention such as:

    • II Color font
    • II Custom axes
    • II Icon / symbols / not text
  3. The teritary category labels (start with III) are orange and allow to know more about the type of upgrade. Every Font upgrade issue should have an orange label:

    • III Expand glyphset
    • III Expand styles
    • III Improve rendering / layout
    • III VF Replacement


The policy is that no one should merge their own PRs. Therefore a reviewer should be assigned to approve the PR before merging. They will make sure the PR is conform to the requirements described in this Guide and will report any issue with the PR.

They either approve and merge or ask for changes —and signal that with labels.

  1. If something is wrong with the PR, the red labels are used:

    • -- Glyphset issue: a problem some glyphs from the font.
    • -- Needs lang/glyphset update: an update from the language or the character set definition of the API (more info about the subtrees lang and glyphsets below).
    • -- Needs Meta/Desc/License changes: problem with METADATA.pb, Description.en_us.html or OFL.txt files.
    • -- Needs upstream resolution: the issue can’t be resolved without a fix in the upstream repository.
    • -- Regression: There are outstanding changes that need to be rollback or debated before merging.
    • -- API tofu: There would be tofu on the specimen page, either because a glyph from the sample text is missing from the font or the glyphset definition (nam files in glyphsets subtree), or because the sample text displays a glyph it shouldn’t (textproto in lang subtree).
  2. When in doubt, the reviewer can call on someone else or ask for more details to the onboarder with these blue labels:

    • -- Needs manager's opinion: This is to apply when Chris and/or Dave are the only one to make a decision about the issue. It is better to list these in the “Pipeline meeting” doc to be sure they don’t remained unnotinced.
    • -- Needs Confirmation: Something curious/weird has been noticed and we need a confirmation from the onboarder that it is on purpose and thus can be approved and merged (or not).

Development (linked issue)

This is the section of the PR panel where we link an issue. Sometimes it doesn’t work, in that case “closing” words can be used in the first comment. For example, “Resolves #465”.

A Pull Request linked to an issue will automatically close the issue when the PR gets merged. Indeed we consider that when a project is part of the main branch of the gitub repo, the issue is not actively worked on anymore by the onboarder. Except if there is a problem in sandbox (in which case we would re-open the issue), the family will end up in the API and this is not something to track along with the issues to do and in progress. As a reminder, this repository is first and foremost the workspace of the onboarders, it is not meant to give hint on releases to users.

The fontbakery report

A new PR will trigger the CI and output a fontbakery report in comment of the PR. Ideally, there should not be any FAILs, and each WARN should be also checked to decide if they are unrelevant.

It is also required to justify any fontbakery FAILS that should be ignored.

Fontbakery has already some exception lists when it comes to RFN and abbreviated font names and camel-cased font name. If the family name of the font is added there, then the FAIL should not yeld anymore (once next version of fontbakery released).

The visual QA

You can find the dowloadable artifacts under checks > Google Fonts QA > qa. This zip file consist in proof and diff images to ensure also a QA by a human eyes.

Check new fonts with the proof reports:

Check updated thanks to the diff reports:

If an important regression is introduced, we should decide to either accept it and merge, or not accept it. For the latter the designer can be asked to roll out the change, or we can eventually onboard the font under a new family name.

Files changed


Check even if there is no FAILs reported by font bakery.


To check even if no FAILs reported by font bakery.



Check the copyright string looks correct.

The lists

As said above, google/fonts repository content is directly linked to the dev-sandbox replicating Every week an engineer from the Fonts team, on call for two weeks, will be responsible to push the changes introduced into the dev-sandbox towards the sandbox server, and the changes introduced into the sandbox towards the actual live server.

An onboarder on call is in charge of notifying the engineer on call about the changed paths in the directory using what we call a “push list”. These are text files directly used by an internal script to push the changes.

  1. The to_sandbox.txt file lists the path that are ready to go to the sandbox servers.

  2. The to_production.txt file lists the path that are ready to go to the live server after being validating in sandbox.

  3. The to_delists.txt file lists all the files that we want to revome from the repository and that should not be displayed on anymore. This file is not linked to any script though, completing it demands a manual intervention from the on call engineer.

A list looks like that:

# New
ofl/notosanskawi #
ofl/playpensans #

# Upgrade
ofl/biorhyme #
ofl/notosanscaucasianalbanian #
ofl/notosanselymaic #

# Metadata / Description / License
ofl/balsamiqsans #
ofl/redrose #

# Axis Registry
axisregistry/ar_retinal_resolution.textproto #

# Lang
lang/languages/ae_Avst.textproto #
lang/languages/af_Latn.textproto #

Two tools are needed to prepare these lists.

The push module

The push module is used to organise the Traffic Jam board, ie. update the PR status and tag the proper list in order to prepare the generation of the push lists text files. Everything that the push module does, you can do it manually from the Traffic Jam board —but it take ages.

gftools gen-push-lists script

A script from gftool is used to generate the push lists text files. Make sure your main branch is in sync and run gftools gen-push-lists path/to/fonts/repo.

The script reads the Traffic Jam board to collect informations:

Once the list are created, it should be pushed to google/fonts thanks to a PR on another branch with a label Tool / Workflow / Repo. Chris should be assigned to review the PR and he will merge it.

Once the PR updating the list is merged, the oncall team should be notified by message in the group chat.

Most of the time the oncall engineer will push the text list without reading it, and they will push the entire font directory wether the change concern only one file or not.

For example pushing a change to a description or metadata orlicense file will result in re-pushing the font family. This can become tricky in the following situations:

Checking the dev/sandbox/prod

It is needed to check each pushed family to make sure that indeed the change was pushed, that it is displayed correctly, and to double-check check previous QA before sending to prod. Most problems could be avoided with a thorough QA before merging, but errors can always happen and the API has the advantage to reflect data errors visually.

Home page


Type Tester



Download button

Relationship between GF / Lang / Glyphsets / Axis Registry

Above we noted that the API could display the font incorrectly. This is because the Google Fonts API doesn’t rely uniquely on the google/fonts repository.

These are the thee subtrees on which an onboarder can interact and what they allow the API to do:

Lang repo

The lang repo contains textprotos to define script, regions and languages.

It happens that some languages don’t have any sample text defined. We can either update the language textproto, or add a sample_text entry in METADATA.pb which would override any existing sample text. This absence of sample text for a script without the addition of a custom one in METADATA.pb would result in an empty specimen page.

Glyphsets repo

Axis registry

The Axis Registry defines:

You know if an axis was correctly implemented by checking

Find everything you need to know about the Axis Registry and the registration protocol in this chapter.

Releases and pull subtree

  1. We need regular releases because these subtrees are also modules used by gftools and fontbakery. For example, if Fontbakery fails a font because it doesn’t display all glyphs of the language’s sample text (although the codepoint is part of a nam file) then it can mean that there is no recent release of the glyphsets package.

  2. Changes to the Lang and Axis Registry repo need to be pulled into the google/fonts repo. The ideal would make a pull subtree at each release of the module to make the sync easier to verify.

    From your local google/fonts clone, run:

    git subtree pull --prefix=axisregistry main


    git subtree pull --prefix=lang main

    Once the main branch from the submodule is pulled, you will need to commit and push in a new branch upstream. Label the PR appropriately Axis Registry or Lang so it gets sorted correclty in the Traffic Jam board.

    Important: When merging a pull request in the google/fonts repo which contains a subtree pull, merge it using the “Create a merge commit” button and not the “Squash and merge” button. If we squash and merge, the subtree’s history is squashed into a single commit which will cause merge conflicts for the next person who has to do a subtree pull.