ANSI color library with support for CI, terminals, and Chromium-based browser consoles.
Ansis is focused on small size and speed while providing rich functionality and handling edge cases.
📣 Announced v4.0.0-beta
- Supports ESM, CommonJS, Bun, Deno, Next.JS
- Works in Chromium-based browsers such as Chrome, Edge, Opera, Brave, Vivaldi
- Default and named import:
import ansis, { red, green, bold, dim } from 'ansis'
- Chained syntax:
red.bold.underline('text')
- Nested tagged template strings:
red`Error: ${blue`file.js`} not found!`
- ANSI styles:
dim
bold
italic
underline
strikethrough
- ANSI 16 colors:
red`Error!`
redBright`Error!`
bgRed`Error!`
bgRedBright`Error!`
- ANSI 256 colors:
fg(56)`violet`
bg(208)`orange`
- Truecolor (RGB & HEX):
rgb(224, 17, 95)`Ruby`
hex('#96C')`Amethyst`
- Automatic fallback: Truecolor → 256 colors → 16 colors → no colors
- Extend base colors with named Truecolor
- Raw ANSI escape codes:
`foo ${red.open}red{red.close} bar`
- Strip ANSI escape codes with
ansis.strip()
- Auto-detects color support across a wide range of environments
- Supports ENV variables and flags:
NO_COLOR
,FORCE_COLOR
,COLORTERM
,--no-color
,--color
- Reliable CLI testing by forcing specific color levels: no color, 16, 256 or truecolor
- Replacement for
chalk
ansi-colors
colorette
picocolors
Note
- Ansis <= v3.17.0 supports Deno 1.x (EOL - 9 Oct 2024)
- Ansis >= v4.0.0 supports Deno 2.x
Dropping support for Deno 1.x is a breaking change, so Deno 2.x support was first introduced inv3.18.0-beta.0
. Use this version until v4 is officially released.
import ansis, { red, cyan, fg, hex } from 'ansis';
ansis.blueBright('file.txt')
red`Error: ${cyan(file)} not found!`
red.bgWhite`ERROR`
fg(215)`ANSI 256 colors`
hex('#E0115F').bold.underline('Truecolor')
The most popular ANSI libraries, similar to Ansis:
chalk, picocolors, colorette, kleur, ansi-colors, kolorist, cli-color, colors-cli, colors.js, tinyrainbow
✅ Compare features 🧩 Handling edge cases 📦 Compare package sizes 📊 Benchmarks
As of 2025, two of the smallest and fastest ANSI libraries are Ansis and Picocolors. Both are recommended by the ES Tooling community as modern replacements for older, larger libraries.
The package size in node_modules
directory:
picocolors
: 6.4 kB (not minimized) - A micro library with basic features.аnsis
: 6.8 kB (minimized) - A powerful library containing all the features you need.chalk
: 44.2 kB (not minimized) - Provides similar functionality to Ansis.
picocolors
: The fastest when applying a single style (e.g.,red
) only.аnsis
: The fastest when applying two or more styles (e.g.,red
+bgWhite
).chalk
: Slower than both Ansis and Picocolors in all use cases.
Caution
Picocolors doesn't handle important edge cases, so it is the fastest and smallest.
Picocolors is faster only in a simple micro-benchmark, which does not reflect real world usage.
In a more complex benchmark, Ansis is much closer to Picocolors results or even faster.
Ansis handles these cases correctly.
ansis.red() // ✅ ''
chalk.red() // ✅ ''
pico.red() // ❌ \e[31mundefined\e[39m
ansis.red(undefined) // ✅ ''
chalk.red(undefined) // ❌ \e[31mundefined\e[39m
pico.red(undefined) // ❌ \e[31mundefined\e[39m
ansis.red(null) // ✅ ''
chalk.red(null) // ❌ \e[31mnull\e[39m
pico.red(null) // ❌ \e[31mnull\e[39m
ansis.reset() // ✅ \e[0m
chalk.reset() // ❌ ''
pico.reset() // ❌ \e[0mundefined\e[0m
See more details about handling input arguments in various libraries.
Ansis and Chalk handle this case and return an empty string without ANSI codes as expected.
However, Picocolors doesn't handle this case.
ansis.red('') // ✅ ''
chalk.red('') // ✅ ''
pico.red('') // ❌ \e[31m\e[39m
Ansis and Chalk add a style break at each new line
to correctly display multi-line text.
However, Picocolors doesn't handle this case.
ansis.bgRed('\n ERROR \n') + ansis.cyan('The file not found!') // ✅
chalk.bgRed('\n ERROR \n') + chalk.cyan('The file not found!') // ✅
pico.bgRed('\n ERROR \n') + pico.cyan('The file not found!') // ❌
Only Ansis handles this very useful use case.
ansis.red`R ${ansis.green`G ${ansis.blue`B`} G`} R` // ✅
chalk.red`R ${chalk.green`G ${chalk.blue`B`} G`} R` // ❌
pico.red`R ${pico.green`G ${pico.blue`B`} G`} R` // ❌
As of 2025, only Ansis, Chalk, and Picocolors are actively maintained, unlike many other libraries:
colorette
: Last updated 2 years agoansi-colors
: Last updated 3 years agokleur
: Last updated 3 years agocolors.js
: Last updated 2 years agocli-color
: Last updated 1 year agocolors-cli
: Last updated 1 year ago
-
If you only use a single style, e.g.,
red('foo')
, Picocolors is the best solution. -
However, if you need more, like combining multiple styles (e.g.,
red
+bold
+bgWhite
),
256 colors, Truecolor, or support for a wide range of environments, then Ansis is the better choice.
- Does support for ESM or CJS matter?
- ✅ Ansis:
ESM
andCJS
- ☑️ Picocolors:
CJS
only - ☑️ Chalk:
ESM
only
- ✅ Ansis:
- Does it matter if a library performs ~60 million or ~100 million ops/sec when outputting to the terminal?
Spoiler: All libraries are more than fast enough.
- ✅ Picocolors
- ☑️ Ansis
- ☑️ Chalk
- Does it matter the unpacked size?
- Does support for ANSI 256 colors or Truecolor with fallback matter?
- ✅ Ansis
- ✅ Chalk
- ❌ Picocolors
- Does handling edge cases matter?
- ✅ Ansis
- ☑️ Chalk
- ❌ Picocolors
- Does supporting a wide range of environments matter?
- ✅ Ansis
- ✅ Chalk
- ❌ Picocolors
- Does keeping your code clean and readable matter?
- ✅ Ansis (default and named import, chained syntax, nested template strings)
- ✅ Chalk (default import, chained syntax)
- ☑️ Picocolors (default import, nested calls)
Explore the list of features, package sizes, and benchmarks compared to similar libraries.
Tip
To keep your code clean and readable:
- Use the chained syntax provided by libraries like
ansis
and `chalk - Avoid nested calls, as they are much slower and less readable than the chained syntax.
import ansis, { red, green, cyan } from 'ansis' // ✅✅ supports both default and named imports
import chalk from 'chalk' // ✅❌ doesn't support named import
import pico from 'picocolors' // ✅❌ doesn't support named import
ansis.red('Error') // ansis ❌ slower than picocolors
chalk.red('Error') // chalk ❌ slower than ansis
pico.red('Error') // picocolors ✅ fastest
red.bold.bgWhite`Error` // ansis ✅✅✅ fastest, short, readable
chalk.red.bold.bgWhite('Error') // chalk ❌☑️✅ slower, short, readable
pico.red(pico.bold(pico.bgWhite('Error'))) // picocolors ❌❌❌ slowest, long, unreadable
green`Create ${blue.bold`React`} app.` // ansis ✅ usability 😊
chalk.green(`Create ${chalk.blue.bold('React')} app.`) // chalk ☑️ usability 🙂
pico.green(`Create ${pico.blue(pico.bold('React'))} app.`) // picocolors ❌ usability 🥴
Tip
Ansis supports nested template strings, so you can colorize text without using parentheses.
- Migrating from
chalk
- Migrating from
colorette
- Migrating from
picocolors
- Migrating from
ansi-colors
- Migrating from
kleur
- Migrating from
cli-color
npm install ansis
ESM
// Default import
import ansis from 'ansis';
// Named imports
import { red, green, bold, dim } from 'ansis';
CommonJS
// Default import
const ansis = require('ansis');
// Named imports
const { red, green, bold, dim } = require('ansis');
Tip
Using template literals you can omit parentheses red(`error`)
→ red`error`
to keep your code clean and readable.
import { cyan, red } from 'ansis';
let file = '/path/to/file.txt';
red`Error: File ${cyan(file)} not found!`;
Ansis correctly renders nested tagged template strings.
import { green, red, yellow } from 'ansis';
red`Red ${yellow`Yellow ${green`Green`} Yellow`} Red`;
red`Error: ${yellow`Module ${green`ansis`} is missing!`} Installation required.`;
All colors, styles and functions are chainable. Each color or style can be combined in any order.
import { red, bold, italic, hex } from 'ansis';
red.bold`text`;
hex('#FF75D1').bgCyan.bold`text`;
bold.bgHex('#FF75D1').cyan`text`;
italic.bold.yellow.bgMagentaBright`text`;
dim
bold
italic
underline
strikethrough
inverse
visible
hidden
reset
Standard Colors | Bright Colors | Standard Backgrounds | Bright Backgrounds |
---|---|---|---|
black |
gray |
bgBlack |
bgGray |
red |
redBright |
bgRed |
bgRedBright |
green |
greenBright |
bgGreen |
bgGreenBright |
yellow |
yellowBright |
bgYellow |
bgYellowBright |
blue |
blueBright |
bgBlue |
bgBlueBright |
magenta |
magentaBright |
bgMagenta |
bgMagentaBright |
cyan |
cyanBright |
bgCyan |
bgCyanBright |
white |
whiteBright |
bgWhite |
bgWhiteBright |
Caution
The redundant grey
, bgGrey
, blackBright
and bgBlackBright
aliases for gray
and bgGray
are deprecated.
The same ANSI codes 90
(gray) and 100
(bgGray) are referred to by different names and aliases in various libraries.
Library | Standardgray bgGray |
UK-spellinggrey bgGrey |
Spec-styleblackBright bgBlackBright |
---|---|---|---|
ansis | ✅ | ❌ | ❌ |
yoctocolors | ✅ | ❌ | ❌ |
kolorist | ✅ | ❌ | ❌ |
colors.js | ✅ | ✅ | ❌ |
picocolors | ✅ | ❌ | ✅ |
tinyrainbow | ✅ | ❌ | ✅ |
colorette | ✅ | ❌ | ✅ |
chalk | ✅ | ✅ | ✅ |
ansi-colors | ✅ | ✅ | ✅ |
kleur (8 colors) | ✅ | ✅ | - |
cli-color | ❌ | ❌ | ✅ |
colors-cli | ❌ | ❌ | ✅ |
However, keeping three separate names for the same color is too much for a small library.
ANSI codes for the gray color:
-
90
is officially "bright black" foreground (i.e.,gray
) in terminal specs. 100
is officially "bright black" background (i.e.,bgGray
) in terminal specs.
Ansis prefers the more intuitive and commonly used names: gray
and bgGray
.
- ✅
gray
,bgGray
- Standard spelling, common used, and intuitive - ❌
grey
,bgGrey
- British spelling, uncommon, and a redundant alias forgray
andbgGray
- ❌
blackBright
,bgBlackBright
- Spec-style names for "bright black", less intuitive, rarely used, awkward for practical use
Note
Supporting both gray
and grey
(or even worse, verbose aliases like blackBright
) introduces unnecessary duplication.
Next Ansis v4 is focused on a clean, minimal API by intentionally avoiding redundant aliases.
256 color functions:
- Foreground:
fg(code)
- equivalent tochalk.ansi256(code)
- Background:
bg(code)
- equivalent tochalk.bgAnsi256(code)
Caution
The legacy ansi256()
and bgAnsi256()
Chalk-compatible aliases are deprecated.
Use fg()
and bg()
instead for setting 256-color foreground and background.
256 colors codes:
See ANSI color codes.
If a terminal supports only 16 colors then ANSI 256 colors will be interpolated into base 16 colors.
import { bold, fg, bg } from 'ansis';
// foreground color
fg(96)`Bright Cyan`;
// background color
bg(105)`Bright Magenta`;
// function is chainable
fg(96).bold`bold Bright Cyan`;
// function is avaliable in each style
bold.fg(96).underline`bold underline Bright Cyan`;
// you can combine the functions and styles in any order
bg(105).fg(96)`cyan text on magenta background`
You can use the hex
or rgb
format.
Foreground function: hex()
rgb()
Background function: bgHex()
bgRgb()
import { bold, hex, rgb, bgHex, bgRgb } from 'ansis';
// foreground color
hex('#E0115F').bold`bold Ruby`;
hex('#96C')`Amethyst`;
rgb(224, 17, 95).italic`italic Ruby`;
// background color
bgHex('#E0115F')`Ruby`;
bgHex('#96C')`Amethyst`;
bgRgb(224, 17, 95)`Ruby`;
// you can combine the functions and styles in any order
bold.hex('#E0115F').bgHex('#96C')`ruby bold text on amethyst background`
The ansis
supports fallback to supported color level.
Truecolor —> 256 colors —> 16 colors —> no colors (black & white)
If you use the hex()
, rgb()
or ansis256()
functions in a terminal not supported Truecolor or 256 colors, then colors will be interpolated.
By default, the imported ansis
instance includes a set of base styles and standard ANSI colors.
To define additional named colors using Truecolor (24-bit RGB), use the ansis.extend()
method.
Tip
Need help picking a color name? Try the Name that Color website - just enter a hex code.
Example:
import ansis from 'ansis';
const myTheme = {
orange: '#FFAB40',
pink: '#FF75D1',
};
// Extend ansis instance with extended colors
ansis.extend(myTheme);
// Destructure extended and base colors
const { orange, pink, red } = ansis;
console.log(ansis.orange.bold('orange bold'));
console.log(orange.italic`orange italic`);
console.log(pink`pink color`);
TypeScript example:
import ansis, { AnsiColors } from 'ansis';
// Extends the built-in `AnsiColors` type with custom user defined color names.
type AnsiColorsExtend<T extends string> = AnsiColors | (T & Record<never, never>);
const myTheme = {
orange: '#FFAB40',
pink: '#FF75D1',
};
// Extend ansis with custom colors
ansis.extend(myTheme);
// Custom logger supporting both built-in and extended styles
const log = (style: AnsiColorsExtend<keyof typeof myTheme>, message: string) => {
console.log(ansis[style](message));
}
log('red', 'message'); // ✅ base color OK
log('orange', 'message'); // ✅ extended color OK
log('unknown', 'message'); // ❌ TypeScript Error
Caution
The AnsiColorsExtend
type is deprecated.
You’ll need to define it manually as in the example above.
Warning
Extended colors must be used as the first item in the style chain:
ansis.orange.bold('orange bold'); // ✅ works as expected
ansis.bold.orange('bold orange'); // ❌ won't work: extended color used as a subchain
By default, output in the terminal console is colored, while output in a file is uncolored.
To force enable or disable colored output, you can use the NO_COLOR
and FORCE_COLOR
environment variables.
Setting the NO_COLOR
variable to any non-empty value will disable color output. For example:
NO_COLOR=1 # Disable colors
NO_COLOR=true # Disable colors
Refer to the NO_COLOR
standard for more details.
The FORCE_COLOR
standard variable is used to control the color output in the terminal.
The behavior of FORCE_COLOR
in Ansis follows the Node.js convention, with a few adaptations:
Value | Description |
---|---|
FORCE_COLOR=false |
Disables colors |
FORCE_COLOR=0 |
Disables colors |
FORCE_COLOR=true |
Auto-detects supported colors; enforces truecolor if none detected |
FORCE_COLOR= (unset) |
Auto-detects supported colors; enforces truecolor if none detected |
FORCE_COLOR=1 |
Enables 16 colors |
FORCE_COLOR=2 |
Enables 256 colors |
FORCE_COLOR=3 |
Enables truecolor |
Important
In Node.js FORCE_COLOR
values of 1
, true
,
and and an empty string (''
) are treated as enabling 16 colors.
In Ansis:
1
- enables exactly 16 colorstrue
- and an empty string trigger automatic color detection (16, 256, or truecolor).
If no colors are detected,truecolor
is enforced.
See:
For example, app.js:
import { red } from 'ansis';
console.log(red`red color`);
You can test the following behaviors by executing the script in the terminal:
node app.js # Colored output in terminal
node app.js > log.txt # Output in file without ANSI codes
NO_COLOR=1 node app.js # Force disable colors
FORCE_COLOR=0 node app.js # Force disable colors
FORCE_COLOR=1 node app.js > log.txt # Force enable 16 colors
FORCE_COLOR=2 node app.js > log.txt # Force enable 256 colors
FORCE_COLOR=3 node app.js > log.txt # Force enable truecolor
The COLORTERM
environment variable indicates color support in terminal emulators.
Its value depends on the terminal and its level of color support. Common values supported by Ansis are:
truecolor
or24bit
- 16 million colorsansi256
- 256 colorsansi
- 16 colors
To force a specific color level, you can set the COLORTERM
variable before running the Node script:
COLORTERM=ansi node script.js # Force enable 16 colors
COLORTERM=ansi256 node script.js # Force enable 256 colors
COLORTERM=truecolor node script.js # Force enable truecolor
Ansis automatically detects the supported color level (none, 16, 256, or truecolor) based on the environment.
To ensure consistent test results across different terminals and environments,
you can explicitly set the desired color level using one of the supported environment variables:
NO_COLOR
, FORCE_COLOR
or COLORTERM
.
Important
You must define the environment variable before importing ansis
.
process.env.NO_COLOR = '1'; // ❌ Doesn't work
import { red } from 'ansis'; // <- Too late! NO_COLOR was undefined when ansis loaded
Instead, create a separate file to set the environment variable and import it first:
import './no-color.js'; // ✅ Sets env variable early
import { red } from 'ansis'; // NO_COLOR is defined
To ensure consistent test output without ANSI codes, you can disable color rendering using the NO_COLOR
environment variable.
Create a file: no-color.js:
process.env.NO_COLOR = '1';
Import this file first in your test:
import './no-color.js'; // disables colors
import { expect, test } from 'vitest';
import { red } from 'ansis';
console.log(red('foo')); // Output: plain "foo", no ANSI codes
test('output should not contain ANSI codes', () => {
const output = red('foo');
expect(output).toBe('foo');
});
Alternatively, use ansis.strip()
to remove color codes from strings in your tests:
import { expect, describe, test } from 'vitest';
import ansis, { red } from 'ansis';
test('should remove ANSI codes from output', () => {
const output = red('foo');
expect(ansis.strip(output)).toBe('foo');
});
File: enable-truecolor.js:
process.env.COLORTERM = 'truecolor';
Test file:
import './enable-truecolor.js'; // enables truecolor
import { red, fg, hex } from 'ansis';
console.log(hex('#FFAB40')('orange')); // uses native ANSI RGB
console.log(fg(200)('pink')); // uses ANSI 256
console.log(red('red')); // uses ANSI 16
File: enable-256colors.js:
process.env.COLORTERM = 'ansi256';
Test file:
import './enable-256colors.js'; // enables 256 colors
import { red, fg, hex } from 'ansis';
console.log(hex('#FFAB40')('orange')); // fallback to ANSI 256 colors
console.log(fg(200)('pink')); // uses ANSI 256 colors
console.log(red('red')); // uses ANSI 16 colors
File: enable-16colors.js:
process.env.COLORTERM = 'ansi';
Test file:
import './enable-16colors.js'; // enables 16 colors
import { red, fg, hex } from 'ansis';
console.log(hex('#FFAB40')('orange')); // fallback to ANSI 16 colors (e.g., bright red)
console.log(fg(200)('pink')); // fallback to ANSI 16 colors (e.g., bright magenta)
console.log(red('red')); // uses ANSI 16 colors
Use cmd arguments --no-color
to disable colors and --color
to enable ones.
For example, an executable script app.js:
#!/usr/bin/env node
import { red } from 'ansis';
console.log(red`text`);
Execute the script in a terminal:
./app.js # colored output in terminal
./app.js --no-color # non colored output in terminal
./app.js > log.txt # output in file without ANSI codes
./app.js --color > log.txt # output in file with ANSI codes
Note
Command-line arguments take precedence over environment variables.
Ansis automatically detects the supported color level:
- Truecolor
- ANSI 256 colors
- ANSI 16 colors
- black & white (no colors)
Ansis has the method isSupported()
that returns a boolean
value whether the output supports ANSI color and styles.
import ansis from 'ansis';
console.log('Color output: ', ansis.isSupported());
There is no standard way to detect which color level is supported.
The most common way to detect color support is to check the TERM
and COLORTERM
environment variables.
CI systems can be detected by checking for the existence of the CI
and other specifically environment variables.
Combine that with the knowledge about which operating system the program is running on, and we have a decent enough way to detect colors.
Terminal | ANSI 16 colors |
ANSI 256 colors |
True Color |
env. TERM |
env. COLORTERM |
Specifically ENV variables |
---|---|---|---|---|---|---|
Azure CI | ✅ | ❌ | ❌ | dumb | TF_BUILD AGENT_NAME |
|
GitHub CI | ✅ | ✅ | ✅ | dumb | CI, GITHUB_ACTIONS | |
GitTea CI | ✅ | ✅ | ✅ | dumb | CI, GITEA_ACTIONS | |
GitLab CI | ✅ | ❌ | ❌ | dumb | CI, GITLAB_CI | |
Travis CI | ✅ | ❌ | ❌ | dumb | TRAVIS | |
PM2 not isTTY |
✅1 | ✅1 | ✅1 | dumb | PM2_HOME pm_id |
|
JetBrains TeamCity >=2020.1.1 |
✅ | ✅ | ❌ | TEAMCITY_VERSION | ||
JetBrains IDEA | ✅ | ✅ | ✅ | xterm-256color | TERMINAL_EMULATOR='JetBrains-JediTerm' | |
VS Code | ✅ | ✅ | ✅ | xterm-256color | truecolor | |
Windows Terminal |
✅ | ✅ | ✅2 | |||
Windows PowerShell |
✅ | ✅ | ✅2 | |||
macOS Terminal | ✅ | ✅ | ❌ | xterm-256color | ||
iTerm | ✅ | ✅ | ✅ | xterm-256color | truecolor | |
Kitty | ✅ | ✅ | ✅ | xterm-kitty | truecolor | |
KDE Konsole | ✅ | ✅ | ✅ | xterm-256color | truecolor |
See also:
Run the command to see the support of some features by various libraries:
npm run compare
Library | Colors support | Features | ||||
---|---|---|---|---|---|---|
- ESM | CJS - named import - naming colors |
16 | 256 | 16m | 🌐 | Fallback | Chained syntax |
Nested template strings `${}` |
LF\n |
Supports ENV vars CLI flags |
ansis ESM CJS ✅ named import ✅ standard
|
✅ ✅ ✅ ✅ | →256 →16 →b&w |
✅ | ✅ | ✅ | NO_COLOR FORCE_COLOR COLORTERM --no-color --color |
chalk v5 ESM ❌ named import ✅ standard |
✅ ✅ ✅ ✅ | →256 →16 →b&w |
✅ | ❌ | ✅ | NO_COLOR FORCE_COLOR --no-color --color |
kolorist ESM CJS ✅ named import ❌ standard |
✅ ✅ ✅ ❌ | →256 →b&w |
❌ | ❌ | ❌ | NO_COLOR FORCE_COLOR |
cli-color CJS ❌ named import ✅ standard |
✅ ✅ ❌ 🛑 | →16 →b&w |
✅ | ❌ | ❌ | NO_COLOR |
colors-cli CJS ❌ named import ❌ standard |
✅ ✅ ❌ 🛑 | →b&w | ✅ | ❌ | ✅ | --no-color --color |
colors.js CJS ❌ named import ❌ standard |
✅ ❌ ❌ 🛑 | →b&w | ✅ | ❌ | ✅ | FORCE_COLOR --no-color --color |
ansi-colors CJS ❌ named import ✅ standard |
✅ ❌ ❌ ❌ | ❌ | ✅ | ❌ | ✅ | FORCE_COLOR |
colorette ESM CJS ✅ named import ✅ standard |
✅ ❌ ❌ 🛑 | →b&w | ❌ | ❌ | ❌ | NO_COLOR FORCE_COLOR --no-color --color |
picocolors CJS ❌ named import ✅ standard |
✅ ❌ ❌ ❌ | →b&w | ❌ | ❌ | ❌ | NO_COLOR FORCE_COLOR --no-color --color |
tinyrainbow ESM ❌ named import ✅ standard |
✅ ❌ ❌ ✅ | →b&w | ❌ | ❌ | ❌ | NO_COLOR FORCE_COLOR FORCE_TTY --no-color --color |
kleur ESM CJS ✅ named import ✅ standard |
❌ ❌ ❌ ✅8 colors |
→b&w | ✅ | ❌ | ❌ | NO_COLOR FORCE_COLOR |
Named import
ESM
import { red, green, blue } from 'lib';
CJS
const { red, green, blue } = require('lib');
Naming colors
- standard: colors have standard names, e.g.:
red
,redBright
,bgRed
,bgRedBright
- non-standard: colors have lib-specific names, e.g.:
brightRed
,bgBrightRed
,red_b
,red_btt
-
16
- ANSI 16 colors likered
,redBright
,bgRed
,bgRedBright
-
256
- ANSI 256 colors methods, e.g.:ansis
:fg(n)
,bg(n)
chalk
:ansi256(n)
,bgAnsi256(n)
cli-color
:xterm(n)
colors-cli
:x<n>
-
16m
- Truecolor methods, e.g.:hex()
,bgHex()
,rgb()
,bgRgb()
-
🌐 - Colored output in Chromium-based browser console:
- ✅ - colored output
- ❌ - b&w output
- 🛑 - fatal error by compilation or in runtime
-
Fallback - Truecolor → 256 colors → 16 colors → no colors
-
Chained syntax
lib.red.bold('text')
-
Nested template strings
lib.red`text ${lib.cyan`nested`} text`
-
LF
- Correct break styles atend-of-line
(\n
).console.log(bgGreen('\nAnsis\nNew Line\nNext New Line\n'))
Compare how different libraries handle various input arguments in their functions.
Library | c.reset() |
c.red() |
c.red(undefined) |
c.red(null) |
c.red('') |
---|---|---|---|---|---|
ansis |
✅\e[0m |
✅'' |
✅'' |
✅'' |
✅'' |
chalk |
❌'' |
✅'' |
❌'undefined' |
❌'null' |
✅'' |
picocolors |
❌undefined |
❌'undefined' |
❌'undefined' |
❌'null' |
❌'ESC' |
tinyrainbow |
❌undefined |
❌'undefined' |
❌'undefined' |
❌'null' |
❌'ESC' |
colorette |
❌'' |
✅'' |
✅'' |
❌'null' |
✅'' |
kleur |
❌[object] |
❌[object] |
❌[object] |
❌'null' |
❌'ESC' |
ansi-colors |
❌'' |
✅'' |
✅'' |
✅'' |
✅'' |
kolorist |
❌undefined |
❌'undefined' |
❌'undefined' |
❌'null' |
❌'ESC' |
colors.js |
❌'' |
✅'' |
❌'undefined' |
❌'null' |
✅'' |
cli-color |
❌- |
❌'ESC' |
❌'ESC' |
❌'ESC' |
❌'ESC' |
colors-cli |
❌- |
❌ Error |
❌'undefined' |
❌'null' |
❌'ESC' |
- ✅
''
- Returns an empty string without ANSI escape codes. This is the correct and expected behavior. - ✅
\e[0m
- Returns the reset escape code. - ❌
'ESC'
- Returns an empty string containing ANSI escape codes, e.g.,\e[31m\e[39m
. - ❌
'undefined'
- Returns the styled stringundefined
. - ❌
'null'
- Returns the styled stringnull
. - ❌
[object]
- Returns an object of the library instance. - ❌
-
- The feature is not supported. - ❌
Error
- Causes a fatal error.
Other arguments are correctly handled by all libraries:
c.red(0) // '0' in red
c.red(false) // 'false' in red
c.red(true) // 'true' in red
c.red(5/'1px') // 'NaN' in red
c.red(1/0) // 'Infinity' in red
Ansis ensures consistent and predictable behavior for edge-case inputs, making it a reliable choice for usage.
Npm package | Dependencies | Is Minified | Unpacked Size | Tarball size |
---|---|---|---|---|
picocolors |
0 | no | 6.4 kB | 2.6 kB |
ansis |
0 | uglified & minified | 6.8 kB | 3.6 kB |
tinyrainbow |
0 | uglified | 8.1 kB | 3.2 kB |
colorette |
0 | no | 17.0 kB | 4.9 kB |
kleur |
0 | no | 20.3 kB | 6.0 kB |
ansi-colors |
0 | no | 26.1 kB | 8.5 kB |
kolorist |
0 | no | 51.0 kB | 8.7 kB |
colors.js |
0 | no | 41.5 kB | 11.1 kB |
chalk |
0 | no | 43.7 kB | 13.4 kB |
cli-color |
5 |
no | 754.0 kB | 216.8 kB |
colors-cli |
0 | no | 511.0 kB | 361.7 kB |
Legend
- Dependencies: Number of dependencies in the package.
- Is Minified: Indicates whether the distributed npm package is minified.
- Unpacked Size: The size of the npm package in the
node_modules/
directory, (incl. dependencies). - Tarball size: The size of the downloaded
*.tgz
package file.
You can check the package size with the following command:just replace thecurl -s -o package.tgz $(npm view <package-name> dist.tarball) && echo "Tarball size: $(stat -f%z package.tgz | awk '{printf "%.2f", $1/1024}') kB"
<package-name>
with your package name.
See also:
- npmjs - show install size of the published package, w/o dependencies
- packagephobia - show total install size, incl. dependencies
- npm download size - show download size
- pkg-size - find the true size of an npm package
- bundlephobia - useless, doesn't show real tarball size of the downloaded npm package
git clone https://github.com/webdiscus/ansis.git
cd ./ansis
npm i
npm run demo
Check the minimum version of your tool required for compatibility with the latest Ansis.
Tool | Version | Compatibility | Supports |
---|---|---|---|
Node.js | v14+ | ✅ Full support | CJS, ESM |
TypeScript/tsc | v5.0+ | ✅ Full support | CJS, ESM |
esbuild | v0.8+ | ✅ Full support | CJS, ESM |
swc | v1.2+ | ✅ Full support | CJS, ESM, FAUX |
tsup | v4.0+ | ✅ Full support | CJS, ESM, FAUX |
tsx | v3.0+ | ✅ Full support | CJS, ESM |
Rollup | v2.0+ | ✅ Full support | CJS, ESM |
Vite | v2.5+ | ✅ Full support | ESM |
Turbo | v1.0+ | ✅ Full support | CJS, ESM |
Webpack | v5.0+ | ✅ Full support | CJS, ESM |
Supports:
- CJS: CommonJS module support.
- ESM: ECMAScript module support.
- FAUX: Fake or non-standard approach to module resolution (seen in swc).
Browser | Version | Colors Supported |
---|---|---|
Chrome | v20+ | TrueColor (16M) |
Safari | v10+ | TrueColor (16M) |
Edge | v12+ | TrueColor (16M) |
Opera | v12+ | TrueColor (16M) |
Brave | v1.0+ | TrueColor (16M) |
Vivaldi | v1.0+ | TrueColor (16M) |
Warning
Firefox doesn't natively support ANSI codes in the developer console.
Caution
The benchmark results are meaningless numbers intended purely to promote the library and increase its popularity. All libraries are more than fast enough. These results only to show the effectiveness of micro-optimizations in the code, which does not impact on real-world usage.
Of course Picocolors will be a little bit faster in a micro-benchmark since it has less code and doesn't handles edge cases.
Taken from the comment by the creator of Chalk.
To measure performance is used benchmark.js.
Warning
Results of vitest benchmark are incorrect.
The vitest benchmark
generate unreal results.
For example, the results of the simple bench:
chalk.red('foo') - 7.000.000 ops/sec
ansis.red('foo') - 23.000.000 ops/sec (x3 faster is incorrect result)
The actual performance results of Chalk and Ansis in this test are very similar.
git clone https://github.com/webdiscus/ansis.git
cd ./ansis
npm i
npm run build
npm run bench
MacBook Pro 16" M1 Max 64GB
macOS Sequoia 15.1
Node.js v22.11.0
TerminaliTerm2
v3.5.0
Important
Each library uses the recommended fastest styling method to compare the absolute performance.
In real practice, no one would use the slowest method (such as nested calls) to style a string when the library provides a faster and a shorter chained method.
For example:
lib.red.bold.bgWhite(' ERROR ') // ✅ faster, shorter, readable
lib.red(lib.bold(lib.bgWhite(' ERROR '))) // ❌ slower, longer, unreadable
The simple test uses only single style.
Picocolors, Colorette and Kleur do not support chained syntax or correct style break (wenn used `\n`
in a string),
so they are the fastest in this simple use case. No function, no performance overhead.
ansis.red('foo')
chalk.red('foo')
picocolors.red('foo')
...
+ picocolors@1.1.1 109.212.939 ops/sec
colorette@2.0.20 108.044.800 ops/sec
kleur@4.1.5 87.800.739 ops/sec
-> ansis@3.5.0 60.606.043 ops/sec -44.5%
- chalk@5.3.0 55.702.479 ops/sec -48.9%
kolorist@1.8.0 37.069.069 ops/sec
ansi-colors@4.1.3 14.364.378 ops/sec
colors@1.4.0 7.060.583 ops/sec
cli-color@2.0.4 2.753.751 ops/sec
colors-cli@1.0.33 897.746 ops/sec
Using only 2 styles, picocolors is already a bit slower, because using the chained syntax is faster than nested calls.
ansis.red.bold('foo')
chalk.red.bold('foo')
picocolors.red(picocolors.bold('foo')) // chained syntax is not supported
...
+ ansis@3.5.0 60.468.181 ops/sec
- picocolors@1.1.1 58.777.183 ops/sec -2.8%
- chalk@5.3.0 47.789.020 ops/sec -21.5%
colorette@2.0.20 33.387.988 ops/sec
kolorist@1.8.0 13.420.047 ops/sec
kleur@4.1.5 5.972.681 ops/sec
ansi-colors@4.1.3 4.086.412 ops/sec
colors@1.4.0 3.018.244 ops/sec
cli-color@2.0.4 1.817.039 ops/sec
colors-cli@1.0.33 695.601 ops/sec
Using 3 styles, picocolors is 2x slower than ansis.
ansis.red.bold.bgWhite('foo')
chalk.red.bold.bgWhite('foo')
picocolors.red(picocolors.bold(picocolors.bgWhite('foo'))) // chained syntax is not supported
...
+ ansis@3.5.0 59.463.640 ops/sec
- chalk@5.3.0 42.166.783 ops/sec -29.0%
- picocolors@1.1.1 32.434.017 ops/sec -45.5% (~2x slower than Ansis)
colorette@2.0.20 13.008.117 ops/sec
kolorist@1.8.0 5.608.244 ops/sec
kleur@4.1.5 5.268.630 ops/sec
ansi-colors@4.1.3 2.145.517 ops/sec
colors@1.4.0 1.686.728 ops/sec
cli-color@2.0.4 1.453.611 ops/sec
colors-cli@1.0.33 590.467 ops/sec
In rare cases, when using 4 styles, picocolors becomes 3.4x slower than ansis.
ansis.red.bold.underline.bgWhite('foo')
chalk.red.bold.underline.bgWhite('foo')
picocolors.red(picocolors.bold(picocolors.underline(picocolors.bgWhite('foo')))) // chained syntax is not supported
...
+ ansis@3.5.0 59.104.535 ops/sec
- chalk@5.3.0 36.147.547 ops/sec -38.8%
- picocolors@1.1.1 17.581.709 ops/sec -70.2% (~3x slower than Ansis)
colorette@2.0.20 7.981.171 ops/sec
kleur@4.1.5 4.825.665 ops/sec
kolorist@1.8.0 3.729.880 ops/sec
ansi-colors@4.1.3 1.514.053 ops/sec
colors@1.4.0 1.229.999 ops/sec
cli-color@2.0.4 1.210.931 ops/sec
colors-cli@1.0.33 481.073 ops/sec
The complex test with deeply nested single styles.
c.green(
`green ${c.cyan(
`cyan ${c.red(
`red ${c.yellow(
`yellow ${c.blue(
`blue ${c.magenta(`magenta ${c.underline(`underline ${c.italic(`italic`)} underline`)} magenta`)} blue`,
)} yellow`,
)} red`,
)} cyan`,
)} green`,
)
+ colorette@2.0.20 1.110.056 ops/sec
- picocolors@1.1.1 1.073.299 ops/sec
-> ansis@3.5.0 847.246 ops/sec -23.7%
kolorist@1.8.0 847.110 ops/sec
- chalk@5.3.0 573.942 ops/sec -48.3%
kleur@4.1.5 471.285 ops/sec
colors@1.4.0 439.588 ops/sec
ansi-colors@4.1.3 382.862 ops/sec
cli-color@2.0.4 213.351 ops/sec
colors-cli@1.0.33 41.097 ops/sec
The benchmark used in colorette
for single styles.
c.red(`${c.bold(`${c.cyan(`${c.yellow('yellow')}cyan`)}`)}red`)
+ picocolors@1.1.1 3.861.384 ops/sec
colorette@2.0.20 3.815.039 ops/sec
-> ansis@3.5.0 2.918.269 ops/sec -24.4%
kolorist@1.8.0 2.548.564 ops/sec
- chalk@5.3.0 2.502.850 ops/sec -35.2%
kleur@4.1.5 2.229.023 ops/sec
ansi-colors@4.1.3 1.426.279 ops/sec
colors@1.4.0 1.123.139 ops/sec
cli-color@2.0.4 481.708 ops/sec
colors-cli@1.0.33 114.570 ops/sec
The picocolors
benchmark, slightly modified.
Added a bit more complexity by applying two styles to the colored word instead of one.
let index = 1e8;
c.red('.') +
c.yellow('.') +
c.green('.') +
c.red.bold(' ERROR ') +
c.red('Add plugin ' + c.cyan.underline('name') + ' to use time limit with ' + c.cyan(++index));
+ picocolors@1.1.1 2.601.559 ops/sec
-> ansis@3.5.0 2.501.227 ops/sec -3.8%
colorette@2.0.20 2.326.491 ops/sec
- chalk@5.3.0 2.129.106 ops/sec -18.1%
kleur@4.1.5 1.780.496 ops/sec
kolorist@1.8.0 1.685.703 ops/sec
ansi-colors@4.1.3 838.542 ops/sec
colors@1.4.0 533.362 ops/sec
cli-color@2.0.4 287.558 ops/sec
colors-cli@1.0.33 97.463 ops/sec
Note
In this test, which is closer to practical use, each library uses the fastest styling method available.
So, chalk
, ansis
, ansi-colors
, cli-color
, colors-cli
and colors
uses chained method, e.g. c.red.bold(' ERROR ')
.
While picocolors
, colorette
and kolorist
uses nested calls, e.g. c.red(c.bold(' ERROR '))
, because doesn't support the chained syntax.
Ansis is a powerful, small, and fast replacement for many similar libraries.
Just update your imports or requires from your previous library to ansis
.
Note
Ansis doesn't supports grey
, bgGrey
, blackBright
or bgBlackBright
- it only provides the commonly used, intuitive gray
and bgGray
.
Migrating from chalk
- import c from 'chalk';
+ import c from 'ansis';
In most use cases, Ansis is compatible with chalk.
c.red.bold('Error!');
c.red(`Error: ${c.cyan.bold('file')} not found!`);
c.hex('#FFA500').bold('Bold orange');
c.rgb(123, 45, 67).underline('Reddish');
c.bgHex('#E0115F')('Ruby');
Replace redundant aliases:
- c.grey('text')
- c.blackBright('text')
+ c.gray('text')
- c.bgGrey('text')
- c.bgBlackBright('text')
+ c.bgGray('text')
Remove unsupported styles like overline
:
- c.red.overline('text');
+ c.red('text');
Replace ANSI 256 color methods:
- c.ansi256(196)('Error');
+ c.fg((196)('Error');
- c.bgAnsi256(21)('Info');
+ c.bg(21)('Info');
Cleaner alternative:
import { red, cyan, fg, bg, hex, rgb, bgHex } from 'ansis';
red.bold`Error!`;
red`Error: ${cyan.bold`file`} not found!`;
hex('#FFA500').bold`Bold orange`;
rgb(123, 45, 67).underline`Reddish`;
bgHex('#E0115F')`Ruby`;
fg(93)`Violet`;
bg(194)`Honeydew`;
Migrating from colorette
- import { red, gray, bold } from 'colorette';
+ import { red, gray, bold } from 'ansis';
In most use cases, Ansis is compatible with colorette:
red(bold('Error!'));
gray('text');
Rewrite to modern style:
red.bold`Error!`;
gray`text`;
Replace redundant aliases:
- import { blackBright, bgBlackBright } from 'colorette';
+ import { gray, bgGray } from 'ansis';
- blackBright('text')
+ gray('text')
- bgBlackBright('text')
+ bgGray('text')
Migrating from picocolors
- import c from 'picocolors';
+ import c from 'ansis';
In most use cases, Ansis is compatible with picocolors:
c.red(c.bold('text'));
c.red('Error: ' + c.cyan(c.bold('file')) + ' not found!');
Modern alternative:
import { red, cyan } from 'ansis';
red.bold`text`;
red`Error: ${cyan.bold`file`} not found!`
Replace aliases:
- c.blackBright('text')
+ c.gray('text')
- c.bgBlackBright('text')
+ c.bgGray('text')
Migrating from ansi-colors
- const c = require('ansi-colors');
+ const c = require('ansis');
In most use cases, Ansis is compatible with ansi-color:
c.red.bold('Error!');
c.red(`Error: ${c.cyan.bold('file')} not found!`);
Cleaner alternative:
import { red, cyan } from 'ansis';
red.bold`Error!`;
red`Error: ${cyan.bold`file`} not found!`;
Replace redundant aliases:
- c.grey('text')
- c.blackBright('text')
+ c.gray('text')
- c.bgGrey('text')
- c.bgBlackBright('text')
+ c.bgGray('text')
Migrating from kleur
- import { red, green, yellow } from 'kleur';
+ import { red, green, yellow } from 'ansis';
Kleur v3+
dropped support for magical chaining (e.g., red.bold()
).
- green().bold().underline('message');
+ green.bold.underline('message');
- yellow(`foo ${red().bold('red')} bar`);
+ yellow(`foo ${red.bold('red')} bar`);
Cleaner alternative:
yellow`foo ${red.bold`red`} bar`;
Replace aliases:
- import { grey, bgGrey } from 'kleur';
+ import { gray, bgGray } from 'ansis';
- grey('text')
+ gray('text')
- bgGrey('text')
+ bgGray('text')
Migrating from cli-color
- const c = require('cli-color');
+ const c = require('ansis');
In common use cases Ansis is compatible with cli-color:
c.red.bold('Error!');
// colorize "Error: file not found!"
c.red(`Error: ${c.cyan.bold('file')} not found!`);
Remove unsupported styles like blink
:
- c.red.blink('text');
+ c.red('text');
Replace ANSI 256 color methods:
- c.xterm(202).bgXterm(236)('Orange on dark gray');
+ c.fg(202).bg(236)('Orange on dark gray');
Cleaner alternative:
import { red, cyan, fg, bg } from 'ansis';
red.bold`Error!`;
red`Error: ${cyan.bold`file`} not found!`;
fg(202).bg(236)`Orange on dark gray`;
Replace redundant aliases:
- c.blackBright('text')
+ c.gray('text')
- c.bgBlackBright('text')
+ c.bgGray('text')
npm run test
will run the unit and integration tests.
npm run test:coverage
will run the tests with coverage.