Skip to content

CJS/ESM ANSI color library for CI, terminals and Chromium-based browser consoles. Compatible with Bun, Deno, Next.JS.

License

Notifications You must be signed in to change notification settings

webdiscus/ansis

Folders and files

NameName
Last commit message
Last commit date

Latest commit

4fdcab5 · Apr 23, 2025
Apr 22, 2025
Mar 29, 2025
Mar 3, 2025
Apr 13, 2025
Mar 29, 2025
Apr 23, 2025
Apr 22, 2025
Apr 22, 2025
Nov 5, 2023
Mar 29, 2025
Feb 16, 2025
Dec 24, 2021
Apr 1, 2024
Apr 23, 2025
Sep 21, 2023
Nov 14, 2023
Feb 21, 2025
Apr 23, 2025
Mar 3, 2025
Apr 22, 2025
Sep 21, 2023
Apr 22, 2025
Apr 22, 2025
Apr 22, 2025
Apr 22, 2025
Mar 29, 2025
Feb 20, 2025
Dec 23, 2024

Repository files navigation

ansis

[ANSI S]tyles

npm node Test codecov downloads install size

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

Ansis demo

Open in StackBlitz

💡 Highlights

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 in v3.18.0-beta.0. Use this version until v4 is officially released.

🛠️ Usage

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')

⚖️ Alternatives

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.

📦 Unpacked size

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.

⚡ Performance

  • 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.

🧩 Edge cases

Absent, undefined or null arguments

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.

Empty string

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

Break style at New Line

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!')   // ❌

Break style at New Line

Nested template strings

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`    // ❌

Nested template strings

🔧 Maintenance

As of 2025, only Ansis, Chalk, and Picocolors are actively maintained, unlike many other libraries:

🤔 Which One Should You Use?

  • 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.

Checklist:

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.

Usage examples

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.


Install

npm install ansis

Default and named import

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');

Tagged template literals

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!`;

Nested template literals

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.`;

Chained syntax

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`;

ANSI Styles

dim bold italic underline strikethrough inverse visible hidden reset

ANSI 16 colors

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.

Color naming in libraries: gray vs grey vs blackBright

The same ANSI codes 90 (gray) and 100 (bgGray) are referred to by different names and aliases in various libraries.

Library Standard
gray
bgGray
UK-spelling
grey
bgGrey
Spec-style
 blackBright
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.

Holywar: Why gray only, without aliases?

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 for gray and bgGray
  • 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.

ANSI 256 colors

256 color functions:

  • Foreground: fg(code) - equivalent to chalk.ansi256(code)
  • Background: bg(code) - equivalent to chalk.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.

Fallback

If a terminal supports only 16 colors then ANSI 256 colors will be interpolated into base 16 colors.

Usage example

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`

Truecolor

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`

Fallback

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.

output

Extend with Custom Colors

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

CLI environment variables

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.

NO_COLOR

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.

FORCE_COLOR

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 colors
  • true - 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

COLORTERM

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 or 24bit - 16 million colors
  • ansi256 - 256 colors
  • ansi - 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

Testing CLI output

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

Disable colors in tests

To ensure consistent test output without ANSI codes, you can disable color rendering using the NO_COLOR environment variable.

Disable via 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');
});

Strip ANSI Codes with ansis.strip()

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');
});

Force truecolor

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

Force 256 colors

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

Force 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

CLI arguments

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.


Color support

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:


Compare the features of most popular libraries

Run the command to see the support of some features by various libraries:

npm run compare

Open in StackBlitz

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

Notes

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

Colors support

  • 16 - ANSI 16 colors like red, redBright, bgRed, bgRedBright

  • 256 - ANSI 256 colors methods, e.g.:

  • 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

Features

  • Chained syntax
    lib.red.bold('text')

  • Nested template strings
    lib.red`text ${lib.cyan`nested`} text`

  • LF - Correct break styles at end-of-line (\n).

    console.log(bgGreen('\nAnsis\nNew Line\nNext New Line\n'))

    Outputs:
    output

Edge cases: input arguments

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'

Legend:

  • '' - 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 string undefined.
  • 'null' - Returns the styled string null.
  • [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.

Compare the size of most popular packages

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:
    curl -s -o package.tgz $(npm view <package-name> dist.tarball) && echo "Tarball size: $(stat -f%z package.tgz | awk '{printf "%.2f", $1/1024}') kB"
    just replace the <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

Show ANSI demo

git clone https://github.com/webdiscus/ansis.git
cd ./ansis
npm i
npm run demo

Compatibility Check

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 Compatibility for ANSI Codes

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.

Benchmarks

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.

Run benchmarks

git clone https://github.com/webdiscus/ansis.git
cd ./ansis
npm i
npm run build
npm run bench

Tested on

MacBook Pro 16" M1 Max 64GB
macOS Sequoia 15.1
Node.js v22.11.0
Terminal iTerm2 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

Simple bench

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 2 styles

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

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

Using 4 styles

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

Deeply nested styles

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

Colorette bench

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

Picocolors complex bench

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.


How to switch to Ansis

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')

Testing

npm run test will run the unit and integration tests.
npm run test:coverage will run the tests with coverage.


License

ISC

Footnotes

  1. Colors supported depends on actual terminal.\ 2 3

  2. The Windows terminal supports true color since Windows 10 revision 14931 (2016-09-21). 2