Libre Barcode and the case for printing barcodes as fonts
Libre Barcode: barcode fonts for various barcode standards.
At a glance
- What is it?
- Libre Barcode is a set of barcode fonts for Code 39, Code 128 and EAN 13 built from UFO sources, with the encoders that generate them written separately and licensed differently from the fonts themselves. The interesting wrinkle for an adopter is that the two halves carry two different licences and the project ships a manual page per barcode standard.
- Who is it for?
- Libre Barcode fits anyone who needs to print a barcode from a layout tool, a report or a label template that cannot call a barcode library, which covers a lot of office printing and a lot of small business labelling. It is the wrong tool for a warehouse pipeline that needs guaranteed encoding correctness, because the font approach puts the encoding step in the text you type and the project does not document a verification path in the repository.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 8 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 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Barcode as a font, so any layout tool can print one
Libre Barcode is a font project. The README puts it in three words, fonts to write barcodes, and that framing explains both what it does well and where its limits are.
The idea is that a barcode is a sequence of bar and space widths, and a font can encode those widths as glyph advances. Once the font is installed, any application that can typeset text can print a barcode: a word processor, a spreadsheet, a PDF tool, a label template, a browser print dialog. No barcode library, no API call, no plugin, no runtime dependency in the printing system.
That is a genuinely different approach from the mainstream, where a barcode is produced by a library that encodes a value and emits a graphic. The font route moves the encoding step into the characters you type, and moves the drawing step into the rasteriser or printer driver that was already there.
The trade is inherent to the approach. The value you want to encode has to survive a round trip through text, so it is limited to what the character set of the chosen standard allows, and the correctness of the output depends on the text actually matching what the scanner expects. Nothing in the project verifies that for you at print time. For a one-off label or a document that is checked by a human, that is a fine trade. For a shipping label that a carrier rejects, it is a different decision entirely.
The fonts are published under the SIL Open Font License, and the project is hosted with a manual page index at graphicore.github.io/librebarcode.
Three standards, and each one has its own manual page
The font families are grouped by barcode standard rather than by style, and the project links a separate manual page for each group.
Code 39 comes in four faces: Libre Barcode 39, Libre Barcode 39 Text, Libre Barcode Extended 39 and Libre Barcode Extended 39 Text. Code 128 comes in two: Libre Barcode 128 and Libre Barcode 128 Text. The EAN 13 group covers more ground than its name suggests, since the heading lists EAN 13 together with EAN 8, UPC-A, UPC-E and 2- and 5-digit add-ons, and the family list for it contains a single entry, Libre Barcode EAN13 Text.
The split between a bar-only face and a Text face is the practical detail that matters for anyone laying out a label. The plain face draws the bars, and the Text face adds the human readable digits underneath, which is what a scanner operator reads when the machine cannot. Whether a face is a text variant is a naming question, and the manual pages are where the mapping from characters to bars is documented.
The naming convention itself carries information. A family named for the Text variant draws the bars and the digits in one, which is exactly what a retail shelf label wants, and a family without it leaves the digits to the layout, which is what you want when the number is already printed elsewhere on the label or needs to be formatted differently.
The three standards are not interchangeable. Code 39 is the most widely readable and the least compact, Code 128 packs more into the same width and is what most modern label printers expect, and EAN 13 is the retail standard with the add-on variants for supplementary codes. The project's coverage of all three, with the add-ons folded into the EAN 13 group, is what makes it usable for mixed labelling work rather than a single niche.
The build chain mixes Node and Python, and pins both hard
Building the fonts from source needs a specific toolchain, and the project is candid about the pinning.
The prerequisites are `git`, a shell such as `bash` or `zsh`, `node` with version management, and `uv` for Python. The version management note is worth reading: `fnm` or `vp env` is recommended, and the documentation states explicitly that `nvm` won't respect the pinned Node.js version. That is a small but real obstacle, since the repository pins a version in `.node-version` and a separate `.python-version` file.
The build itself is a sequence of steps, each run from the project directory:
path/to $ git clone [email protected]:graphicore/librebarcode.git
path/to $ cd librebarcodeThen the JavaScript dependencies and the pinned Python environment:
path/to/librebarcode $ npm install
path/to/librebarcode $ npx bower install
path/to/librebarcode $ uv syncAnd the build, where the comment notes that `uv run` ensures the Python venv is on PATH:
path/to/librebarcode $ uv run ./app/bin/buildAllThe results land in two directories, with the fonts in `fonts/` and the UFO sources in `sources/`. The presence of `sources/` in the output is the giveaway about the design: the fonts are generated from UFO sources, so the source of truth is an editable design format rather than the shipped binaries.
The Python side is tightly pinned in pyproject.toml. It requires Python exactly `==3.9.*`, and it pins fontmake to 2.3.0, font-v to 1.0.5, gftools to 0.5.2, setuptools to 79.0.1 and ttfautohint-py to 0.6.0. The uv configuration adds constraint dependencies for fonttools 4.18.1, protobuf 3.19.6 and ufo2ft 2.19.2, which is how transitive versions are held still across a build that mixes two ecosystems.
A ttfautohint shim exists because fontmake 2.3.0 calls a binary
One detail in the packaging deserves an explanation, because it tells you how the project handles a dependency that behaves differently across versions.
The comment in pyproject.toml says ttfautohint-py ships the ttfautohint binary as package data and does not install a console script, while fontmake 2.3.0 invokes plain `ttfautohint` via subprocess and expects it on PATH. The project solves this with a shim entry in the scripts table:
[project.scripts]
ttfautohint = "ttfautohint.cli:main"The comment goes on to explain that newer fontmake uses the Python API directly, and that 2.3.0 is pinned for reproducible output. So the pin is not nostalgia. The build depends on the older fontmake behaviour, and the shim exists to make the older invocation style work inside a uv managed venv.
There is a second reason the package is shaped this way. The build system requires setuptools as a build requirement, and the tool configuration sets `py-modules = []` with the comment that this tells setuptools not to go looking for Python modules in the repository. The wheel is empty apart from the ttfautohint entry, because the repository is not a Python package, it is a font project that uses Python as its build tooling.
The same split shows on the JavaScript side. The package manifest declares the project name as librebarcode with version 0.0.0, and its test script is the standard placeholder that echoes an error and exits 1, which is a candid admission that there is no JavaScript test suite. The dependencies are mostly toolchain pieces: bower for the front end assets, fontkit, helmsman, jsdom, libxmljs, lie and requirejs, plus a forked commander pulled from a specific branch of the project's own repository.
Two licences, and the split runs through the repository
The licensing section is short but the distinction matters, and the repository files confirm it.
The fonts are licensed under OFL, and there is an `OFL.txt` at the root. The barcode font generators and encoders are GPL3+, and the package manifest records the repository's own licence as GPL-3.0-or-later.
So the repository carries two licences for two different kinds of asset, and the split is not cosmetic. The OFL applies to the font binaries you ship in a product or a document. The GPL applies to the tools that generate those fonts and to the encoders, which means the build chain is copyleft software.
For a person who installs the fonts and prints barcodes, the OFL is the licence that governs what they do next, and it is a permissive one designed for exactly that use. For someone who wants to modify the generators, the GPL is the obligation to read, and anyone redistributing a modified generator carries it forward.
The `AUSTHORS.txt` and `CONTRIBUTORS.txt` files sit alongside the licence files, which is the normal way to record attribution, and the OFL itself requires that the reserved font names not be used for modified versions, so anyone rebranding a face needs to check that rule rather than assume it is open.
The repository default branch is `master`, and the site is generated from `index.md` with Jekyll conventions: `_config.yml`, `_includes/` and `_layouts/`, plus a `documentation/` directory that holds the manual pages, `web_assets/` for the site assets and `app/` for the build scripts and encoders.
The release tags lag the code by years, which is the real maintenance caveat
Here is the fact that deserves the most attention from anyone considering depending on this project.
The recent releases are v1.008 on 2021-09-08, pre-v1.008 on 2020-12-16, and v1.003-alpha on 2017-09-15. The latest release title also mentions Version 1.005, which suggests the numbering has been reused across more than one artefact. Meanwhile the last push to the repository was on 2026-10-18, and the repository is not archived.
So the code is being worked on while the published release is five years old. The obvious reading is that the fonts on the download page are what most people use, and the recent commits are fixes, tooling updates and the kind of dependency maintenance that does not produce a new version number. The build chain, for instance, is pinned to a specific fontmake version and a specific Python, both of which need attention as time passes, and those are exactly the kind of change that lands without a release tag.
The practical consequence for an adopter is that the release tag and the branch are different things. If you need a repeatable, auditable artefact, pin to a tag and accept that it is the 2021 code. If you need the current fixes, build from the branch and accept that no version marker tells you what you are running.
There is also no test suite to fall back on for the JavaScript side, since the test script is a placeholder that exits with an error. The `tests/` directory does not appear in the top level listing, so the verification story for this project is visual: you generate a barcode, print it, and scan it.
Against a barcode library, the difference is who does the encoding
The realistic alternative to a barcode font is a barcode library, and the difference in approach comes down to where the encoding step happens.
A library takes a value, encodes it according to the standard, and gives you a graphic or a set of drawing commands. You call it from code, and the correctness of the output is the library's responsibility, typically covered by its own test suite. That is the right shape for a server generating labels at volume, a scanner talking to a database, or anything where a wrong barcode has a real cost.
A font moves the encoding into the text. You type the characters, the font maps them to bars, and the printer renders them. Nothing validates that the characters are a legal encoding of what you meant, and nothing checks the result. The gain is that the printing path is unchanged, which matters when the alternative is wiring a code generator into a reporting tool, a document template, or a design application that has no scripting hook.
The middle ground is worth naming: generate the barcode once as an image with a library, then place that image in the layout. You get library-grade encoding and no runtime dependency, at the cost of an asset to keep in sync with the data. The font approach wins when the data changes often enough that regenerating assets is a chore, which is the case for a template that prints variable product codes all day.
The deciding question is what happens when a barcode is wrong. With a font, the failure is discovered by a human with a scanner or by a carrier rejecting a parcel, and the recovery is to check the manual page for the standard and recheck the character mapping. With a library and a verification step, the failure happens before the label is printed. That is the boundary between the two approaches, and it is a workflow decision rather than a technical one.
Editorial conclusion
Libre Barcode fits anyone who needs to print a barcode from a layout tool, a report or a label template that cannot call a barcode library, which covers a lot of office printing and a lot of small business labelling. It is the wrong tool for a warehouse pipeline that needs guaranteed encoding correctness, because the font approach puts the encoding step in the text you type and the project does not document a verification path in the repository. Before adopting, check three things: that your layout tool maps characters to the glyphs the font expects, which the per-standard manual pages describe, that the licence split suits you since the fonts are OFL and the generators and encoders are GPL3+, and that your build environment can meet the pinned versions, Python 3.9 exactly and Node 18.20.8. The last push was on 2026-10-18 while the most recent tagged release is v1.008 from 2021-09-08.
Frequently asked questions
What is Libre Barcode and which barcode standards does it support?
It is a font project that provides barcode fonts for Code 39, Code 128 and EAN 13, with the EAN 13 group also covering EAN 8, UPC-A, UPC-E and 2- and 5-digit add-ons. Each standard has its own manual page on the project site.
How do I build the Libre Barcode fonts from source?
Clone the repository, run `npm install` and `npx bower install`, then `uv sync` to set up the pinned Python environment, and run `uv run ./app/bin/buildAll`. The fonts end up in `fonts/` and the UFO sources in `sources/`, and the build needs Python exactly 3.9.x and Node 18.20.8.
What licence applies to the Libre Barcode fonts and the build tools?
The fonts are licensed under OFL, with the licence text at the root of the repository, and the barcode font generators and encoders are GPL3+. The package manifest records the repository licence as GPL-3.0-or-later.
Why does the Libre Barcode build need a ttfautohint shim?
The ttfautohint-py package ships the binary as package data without installing a console script, and fontmake 2.3.0 invokes plain `ttfautohint` through subprocess expecting it on PATH. The project adds a `[project.scripts]` entry exposing the Python CLI wrapper, and pins fontmake 2.3.0 for reproducible output.
Is Libre Barcode still being worked on?
The last push to the repository was on 2026-10-18 and the repository is not archived, but the most recent tagged release is v1.008 from 2021-09-08. The branch and the release tag are therefore different things, so pin deliberately if you need a repeatable artefact.
Official sources
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.
[](https://hysenlabs.com/projects/graphicore-librebarcode)Was this useful?