svg2ttf: turning SVG font sources into TrueType binaries
SVG -> TTF font convertor
At a glance
- What is it?
- The SVG font format is a readable XML file that describes glyphs as outlines, which makes it a good authoring format and a bad delivery format, because no operating system will install it. svg2ttf is the converter that takes one to the other, and the interesting part of its documentation is the place where it admits what it does not do, which is everything the format supports beyond the needs of an icon font.
- Who is it for?
- svg2ttf fits a developer producing an icon font, where the source format is authored in a vector editor and the delivered format has to be installable, and it fits a developer who wants to read a working implementation of the font table writing and optimising code. It does not fit somebody building a text font with kerning and complex layout.
- 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 174 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What it does, and where it came from
svg2ttf converts SVG fonts to the TrueType format. It was written initially for a web service that lets people build icon fonts, and the readme says that you may find it useful for your own projects.
The reason the conversion exists at all is worth a paragraph, because it explains the tool's design. The SVG font format is an XML document that describes a font as a set of glyphs, each one a path, plus the metrics. That is a wonderful authoring format: it is text, it diffs, it can be produced by a vector editor, and a human can read what the glyph is supposed to be. It is a terrible delivery format, because no operating system installs an XML file as a font, and because the format has no notion of the tables that a font binary needs to carry: the version, the naming records, the horizontal metrics, the glyph outlines, the character-to-glyph mapping, and the rest.
So the conversion is the act of taking a human-editable description and producing the binary that a font rasteriser can actually load, and doing it correctly is a great deal of work. The readme says so, in a sentence addressed to developers: the internal API is similar to the one in a well known font editor, and since the primary goal is generating iconic fonts, the sources can lack some specific TrueType and OpenType features such as kerning. And then the punchline: the current code is a good base for development, because it will save you tons of hours of implementing correct writing and optimising of the font tables.
That is an unusual and useful framing. The tool is not presented as a product that handles fonts; it is presented as a well-tested implementation of the tedious part, offered to people who need to extend it. The admission about kerning is in the same breath, which is the right place, because a reader who is about to build a text font needs to know immediately that this is the wrong tool for them.
The package is MIT licensed, published to the package registry, and the source repository is the one for the service that inspired it.
The command line, and the flag that is not documented
There is a command line tool, and it is the first thing the readme shows after the description.
``` bash npm install -g svg2ttf
bash svg2ttf fontello.svg fontello.ttf
Two positional arguments: the source file and the destination file. The tool is installed globally, and the invocation is the one you would expect from a converter, which is the sign of a tool whose author wanted it to be used from a script as easily as from a terminal.
And then there is a flag that the readme never mentions, which you can only discover by reading the package manifest. The scripts section has an entry for regenerating a test fixture, and it invokes the tool with a timestamp option.
"update_fixture": "./svg2ttf.js --ts 1457357570703 test/fixtures/test.svg test/fixtures/test.ttf" ```
Two things are visible there. The first is the timestamp option, whose value is a fixed number, and the second is the shape of the number: it ends in three digits that are not zeroes, which is the signature of a millisecond timestamp rather than a second one.
The option itself is documented in the API section, where it is described as a Unix timestamp in seconds used to override the creation time, and it is listed as optional. So the command line tool accepts it even though the readme does not say so, and the flag name in the script is the short form of the option in the API.
And the reason a fixed timestamp is used is the interesting part. The creation time of a font goes into the font's header, and the header goes into the binary, so a font built from the same source twice would differ unless the time is pinned. The test fixture is a committed binary, and the script regenerates it. If the timestamp moved with the wall clock, every regeneration would produce a different file and the fixture would churn on every commit. Pinning it makes the build reproducible, which is a small piece of engineering discipline that is easy to miss and expensive to retrofit.
So there are two lessons in that one script line. A converter that writes timestamps into its output needs an override if its output is ever checked in. And a test fixture that is a binary file should be regenerated by a script that is committed, so that a reader can see how the expected file was produced.
The API, and what the options are for
The function takes the SVG font content as a string and a set of options, and returns a buffer.
``` javascript var fs = require('fs'); var svg2ttf = require('svg2ttf');
var ttf = svg2ttf(fs.readFileSync('myfont.svg', 'utf8'), {}); fs.writeFileSync('myfont.ttf', new Buffer(ttf.buffer)); ```
The signature is small and the options are the metadata that a font binary has to carry and that an SVG font source does not always supply. There is a copyright string, a description, a manufacturer url, and a version string, which the readme says can be given either as a full string or as a bare pair of numbers, which is a small kindness to a caller who has a version number rather than a version label. And there is the creation time option we have already met.
The returned value deserves a note, because it is the one genuinely unusual thing about the interface. It is a byte buffer object, an internal one, described as similar to the data view interface, and its own buffer property is the array of bytes holding the font. So you write the font to a file by taking that property and handing it to a file write.
The reason the project has its own byte buffer rather than returning an array directly is that writing a font is not a sequential stream of bytes. A font is a set of tables, and the writer has to fill in offsets and lengths in the header and the table directory after it knows how big each table turned out to be. That means going back and patching earlier bytes. A growable buffer that you can write at an offset and come back to is the natural tool for that, and a plain array of bytes is not, because you cannot grow it once you have handed it to a file writer.
So the interface shape is a direct consequence of the format. The buffer is not an abstraction for its own sake; it exists because the font format requires a second pass over the data, and the library hides that by giving the caller a single property to write out.
And the return value being a buffer rather than a file path is what makes the tool usable in a build pipeline, where the font has to end up in a directory that the caller knows about.
The dependency list, and what each one is doing
The dependency list is short and every entry has an obvious job, which is the mark of a library that has been trimmed rather than one that has just been started.
There is an XML implementation for the environment, which parses the SVG font document, since the format is XML and the language has no built-in parser. There is a path library, which handles the path data inside the glyphs, including the transformations and the coordinate system differences between the two formats. There is a converter from cubic curves to quadratic ones, which is there because TrueType outlines are quadratic and the source format allows cubic segments, so the conversion is a required step rather than an optional one.
There is a byte buffer library, which is the one we have already met, since the tool returns its own buffer type and the dependency provides it. There is a general utility library, and an argument parser for the command line.
The two that are most interesting are the XML parser and the curve converter, because together they are the two places where the format boundary actually is. Everything else in the conversion, once you have the glyph outlines and the metadata, is the writing of the tables, and that is the part this project has done well enough to tell other people to build on.
The development dependencies are as informative as the runtime ones. There is a linter, with a configuration file at the root and a shared style configuration. And there is an independent font library, used as a development dependency, which is almost certainly what the tests use to open the produced file and check its contents.
That last one is the detail worth pausing on. Verifying a converter by comparing bytes is fragile, because a font table has padding and alignment rules and the exact bytes depend on the writer's choices. Verifying it by opening the result with a different implementation and asking whether the glyphs and the metrics are right is a much stronger check, and it is the check an independent library enables. A test suite that parses its own output with the same code that produced it proves very little.
The test runner is the one built into the language, invoked after the lint step, and the fixture directory holds the committed expected output. So the test story is: lint, run the tests, and compare against a committed binary that a documented script regenerates.
The internals, and the maintenance arrangement
Two things in the readme are worth closing on, and they are the two that describe the project rather than the tool.
The first is the statement that the internal API is similar to the one in a well known font editor. That is a deliberate architectural choice: the internals are structured as a pipeline of table writers rather than as a single large function, and the design of that pipeline follows a design that a font editor author already established. For a reader who wants to extend the tool, the practical consequence is that the code is arranged in a way that is already familiar to somebody who has worked in that area, and that the functions are named after the tables they write.
It also explains the file layout. There is a small directory of implementation modules, a file that is the public entry point, a file that is the command line program, and a file whose name suggests it reports information about a font, which is the kind of utility you need when a conversion produces a file that will not load and you need to know what is in it.
And there is a change log at the root, which for a project at version six with a long history is the document that tells you what changed when the format specification moved, because it did move, and a converter has to move with it.
The second thing is the maintenance arrangement at the end of the readme, which is a sponsorship programme. The maintainers of this package and of thousands of others are working with a commercial support and maintenance provider, and an organisation can subscribe to get the maintainers of the exact dependencies it uses to do the work.
That model is worth understanding because it is a specific answer to a specific problem. A converter of this kind has a long tail of users who need it to work and do not need to change it, and a small number who need to change it, and the arrangement gives the first group a way to pay for the second group's time. The price is a commercial relationship in the middle of an open source dependency, and the benefit is that the package has been maintained through format changes rather than abandoned when its author moved on.
Which is the other thing to say about this project. It is a small, focused, MIT licensed converter whose main claim is not that it is complete but that it is a good base, and whose maintenance has been arranged so that it will still be here when the next format change arrives.
Editorial conclusion
svg2ttf fits a developer producing an icon font, where the source format is authored in a vector editor and the delivered format has to be installable, and it fits a developer who wants to read a working implementation of the font table writing and optimising code. It does not fit somebody building a text font with kerning and complex layout. Verify first which features your source font actually uses, because the readme is explicit that kerning and other table features can be absent, and that the tool was written for icon fonts, that you set the creation timestamp if you want reproducible output, and that you check the produced file with an independent font library if the output matters to you.
Frequently asked questions
What does the svg2ttf package do?
It converts an SVG font source into a TrueType binary. The SVG format describes glyphs as paths in a readable XML file, which is good for authoring and unusable as a delivered font, and the converter writes the tables a font binary needs. It was written initially for an icon font service and is offered as a general tool.
How do I use svg2ttf from the command line?
Install it globally with the package manager, then pass the source file and the destination file as two arguments. There is also a timestamp option that overrides the creation time recorded in the font, which the readme documents as an API option rather than as a command line flag.
What options does the svg2ttf function take?
An optional copyright string, a description, a manufacturer url, a version string that can be given either as a label or as a bare number pair, and a Unix timestamp in seconds used to override the creation time. The function returns a byte buffer whose own buffer property holds the font bytes.
Does svg2ttf support kerning and other advanced font features?
Not necessarily. The readme says the primary goal is generating iconic fonts, so sources can lack specific TrueType and OpenType features such as kerning. It presents the code as a good base for development for people who need to extend it, which is a different proposition from being a complete font builder.
How are the svg2ttf tests written?
The suite runs the language's own test runner after a lint step, and it depends on an independent font library as a development dependency, so the produced file can be opened and checked by a different implementation rather than compared byte for byte. The expected output is a committed binary fixture that a documented script regenerates with a fixed timestamp so the build stays reproducible.
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/fontello-svg2ttf)Was this useful?