figures: Unicode symbols for CLIs, with ASCII fallbacks for terminals that lack them
Unicode symbols with fallbacks for older terminals
At a glance
- What is it?
- figures is a tiny npm package that gives a command line program a set of symbols, and swaps them for ASCII approximations when the terminal cannot render Unicode. It is a single dependency-free idea that solves a problem every CLI author hits on Windows Console Host.
- Who is it for?
- figures suits anyone writing a command line interface whose output contains status symbols, especially if that tool also runs on Windows Console Host, where unsupported glyphs turn into garbage. It is the wrong choice if you need a configurable icon set, a colour palette, or a terminal detection strategy beyond the single is-unicode-supported check, and it is the wrong choice if your output is going to a log file rather than a terminal.
- 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 35 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
The problem is one character set and a lot of terminals
The README opens with the constraint that drives the whole package. Terminals such as Windows Console Host, and CMD, only support a limited character set, the README links to code page 437. That limitation is the reason a tool that prints a check mark or a warning triangle behaves differently on a Linux terminal and on a Windows one, and the reason the same program that looks tidy in one place prints mojibake in another. figures is an open source npm package for Unicode symbols with fallbacks for older terminals, and it is a very small answer to that problem. The package description in the metadata is the same one line: Unicode symbols with fallbacks for older terminals. What the package does is hold two tables of symbols and pick between them based on what the terminal can handle, so the calling code does not have to think about it. The topics the repository carries are command-line, command-line-utility, node-module, npm-package, terminal, unicode and unicode-symbols, which is an accurate summary of a package that is about ten kilobytes of data and one runtime check. Installing it is a single command:
npm install figuresOne dependency, one file, ESM only
The repository is small enough to read in one sitting. The top-level entries are index.js as the implementation, index.d.ts for the types, index.test-d.ts for the type tests, test.js for the runtime tests, package.json, a license file, a .npmrc, an .editorconfig, a .gitattributes and a screenshot. The package.json shows a module with a type of module, meaning it is ESM only, and the exports map has just two entries, types pointing at index.d.ts and default pointing at index.js. The fields that decide how the package behaves in your project are these:
"name": "figures",
"version": "6.1.0",
"type": "module",
"sideEffects": false,
"engines": {
"node": ">=18"
"dependencies": {
"is-unicode-supported": "^2.0.0"The engines field requires Node 18 or newer, and the package declares sideEffects as false, so a bundler can drop it entirely if nothing uses it. The files array lists only index.js and index.d.ts, so nothing else ships. The single runtime dependency is is-unicode-supported at version 2, which is the module that answers the only question that matters at startup, can this terminal render Unicode symbols. The test script is xo, then ava, then tsd, so the package is linted, unit tested and type tested in one command. The licence is MIT and the author is Sindre Sorhus.
Three exports, and the difference between them is the whole API
The public surface is small and the README is explicit about what each piece is for. The default export, figures, is an object of symbols to use on any terminal, which means the values are already resolved to whichever set fits the current terminal. mainSymbols is the object of symbols to use when the terminal supports Unicode symbols, and fallbackSymbols is the object for terminals that do not. Then there is replaceSymbols, a function that takes a string and returns the input with fallback symbols substituted if the terminal has poor Unicode support. That last one is the part that changes how you use the package. Rather than composing your output out of figures.tick and hoping, you can build the string however you like and then pass it through replaceSymbols at the point of output, which means a single call site handles the whole problem instead of every interpolation site. The README example does exactly that, printing a check mark followed by a word, and showing the Unicode version on terminals that support it and the fallback version elsewhere.
replaceSymbols takes an option that overrides the detection
The options object on replaceSymbols is where the interesting behaviour lives, and it has one key. useFallback is a boolean, and the default is true if the terminal has poor Unicode support. Whether to replace symbols with fallbacks is what the option controls, and the README explains the case that matters: setting it to true always uses fallback symbols, whether the terminal has poor Unicode support or not. That is a testing and screenshot feature as much as anything else. If you are generating output for a terminal you cannot see, such as in a CI log or a captured image, forcing the fallback path means the output you check is the output your users with old terminals will see. The option is described as belonging to a replaceSymbols function whose return value is the input with replaced fallback symbols, so the transformation is applied to the whole string rather than to individual symbols. The README also notes that the option can be set to true, which is the same statement, and that the default follows the detected capability, which means the typical call site needs no options at all.
Not every symbol has a fallback, and the table shows which
The symbol table in the README is the reference for what you can actually rely on, and its structure tells you something important. The README states that fallback characters are only shown when they differ from the main ones, which means the table has empty fallback cells for every symbol where the ASCII and Unicode forms coincide or where no ASCII approximation exists. Reading the table, the common status icons do have fallbacks. The tick has a radical-sign-like alternative, the info symbol falls back to a plain letter i, the warning symbol to a double exclamation mark, and the cross to a multiplication sign. The circle family maps onto parenthesised ASCII forms, so a hollow circle becomes a pair of parentheses and a filled circle becomes an asterisk in parentheses, and the checkbox symbols fall back to bracketed forms. The pointer falls back to a greater-than sign, the hamburger to an equivalence sign, the lozenge to a filled diamond. The block and shade characters, the triangles, the arrows, the comparison operators, the subscripts and the music notes have no fallback listed at all, which means those are Unicode-only in practice.
Where this stops being enough
There is a clear boundary to what this package does, and it is worth naming before you build on it. The detection is a single boolean, and the is-unicode-supported dependency is what provides it, and the README describes the fallback choice as being made per terminal. There is no configuration for the symbol set itself, no way to swap the table for your own icons, and no documented way to override a single symbol. The replaceSymbols function scans a string, which means the symbols it recognises are the ones in the table, so a custom glyph you introduce yourself is not a candidate for replacement. That is a reasonable design for the common case, and it means the package is not the place to control a brand's iconography. There is also no colour and no theme, which is a deliberate boundary, since a separate package exists for that. A second limitation is more mundane and matters for servers. The detection is about the terminal, and a program whose output is redirected to a file or a log collector is no longer talking to a terminal at all, so the symbol choice made for a human viewing a screen is the wrong one for a log pipeline that expects plain text. The README does not address output redirection, and the practical consequence is that a program that prints symbols unconditionally will still put them into its log files.
Editorial conclusion
figures suits anyone writing a command line interface whose output contains status symbols, especially if that tool also runs on Windows Console Host, where unsupported glyphs turn into garbage. It is the wrong choice if you need a configurable icon set, a colour palette, or a terminal detection strategy beyond the single is-unicode-supported check, and it is the wrong choice if your output is going to a log file rather than a terminal. Verify first that the fallback characters your output needs are actually present in the table, since only some symbols have one, and that the is-unicode-supported detection matches the terminals your users actually run.
Frequently asked questions
What does the figures npm package do?
It provides a set of Unicode symbols for command line output and substitutes ASCII fallbacks when the terminal has poor Unicode support, so a CLI looks consistent on terminals such as Windows Console Host that only support a limited character set.
How do I install figures?
With npm install figures. The package requires Node 18 or newer, is an ES module only, and its single runtime dependency is is-unicode-supported.
What is the difference between figures, mainSymbols and fallbackSymbols?
The default export figures is resolved for the current terminal, mainSymbols holds the Unicode versions and fallbackSymbols the ASCII ones. You would reach for mainSymbols or fallbackSymbols directly when you want to bypass the detection.
Can I force figures to always use the fallback symbols?
Yes. Pass useFallback set to true in the options of replaceSymbols, which the README says always uses fallback symbols whether the terminal has poor Unicode support or not.
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/sindresorhus-figures)Was this useful?