Skip to main content

Guide

chalk vs kleur vs colorette (2026)

Compare chalk, kleur, and colorette for terminal colors in Node.js. Bundle size, ESM support, chaining API, color detection, TypeScript, and which terminal.

·PkgPulse Team·
0

TL;DR

chalk is the most popular terminal coloring library — chainable API (chalk.red.bold("text")), automatic color level detection (256 colors, Truecolor), and an ecosystem of utilities built around it. kleur is the lightweight alternative — 2.5KB vs chalk's 15KB, same chaining API, no color detection (just uses whatever the terminal supports). colorette is the smallest — 1.5KB, function-based (no chaining), and faster for simple use cases. All three work with Node.js and modern terminals. For CLIs with complex styling, use chalk. For lightweight scripts and build tools, use kleur or colorette.

Key Takeaways

  • chalk: ~200M weekly downloads — most popular, auto color detection, 256/Truecolor, chalk.level
  • kleur: ~50M weekly downloads — 2.5KB, same chain API, lighter alternative
  • colorette: ~60M weekly downloads — 1.5KB, function-based, fastest, used by Vite/Rollup
  • chalk v5 is ESM-only — use chalk@4 for CommonJS or kleur/colorette for CJS + ESM
  • None are needed in Node.js 22+ which has util.styleText() for simple cases
  • colorette is preferred in build tools (Vite uses it) — small footprint matters there

PackageWeekly DownloadsBundle SizeESMCJSChain API
chalk~200M~15KB✅ v5✅ v4
kleur~50M~2.5KB
colorette~60M~1.5KB❌ Functions

chalk

chalk — the terminal string styling standard:

Basic usage

import chalk from "chalk"

// Basic colors:
console.log(chalk.red("Error: Package not found"))
console.log(chalk.green("Success: Package published"))
console.log(chalk.yellow("Warning: Deprecated package"))
console.log(chalk.blue("Info: Fetching npm data"))
console.log(chalk.gray("Debug: request to registry"))

// Background colors:
console.log(chalk.bgRed.white(" FAIL "))
console.log(chalk.bgGreen.black(" PASS "))

// Modifiers:
console.log(chalk.bold("Important"))
console.log(chalk.dim("Secondary info"))
console.log(chalk.italic("Emphasis"))
console.log(chalk.underline("Underlined"))
console.log(chalk.strikethrough("Deprecated API"))

Chaining

import chalk from "chalk"

// Chain styles:
console.log(chalk.red.bold("Error"))
console.log(chalk.blue.underline("Link"))
console.log(chalk.bgYellow.black.bold(" WARNING "))

// Template literals:
const pkg = "react"
const score = 95
console.log(chalk.cyan(`Package: ${pkg}`) + " " + chalk.green(`Score: ${score}/100`))

// Nested:
console.log(chalk.blue(`Blue ${chalk.red("Red")} Blue again`))

256 colors and Truecolor

import chalk from "chalk"

// 256-color palette (0-255):
console.log(chalk.ansi256(196)("Red-ish"))
console.log(chalk.bgAnsi256(21)("Blue background"))

// Truecolor (RGB):
console.log(chalk.rgb(255, 136, 0)("PkgPulse orange"))
console.log(chalk.hex("#FF8800")("PkgPulse orange (hex)"))
console.log(chalk.bgHex("#FF8800").black("Orange background"))

// HSL:
console.log(chalk.hsl(30, 100, 50)("Warm orange"))

Color level detection

import chalk, { Chalk } from "chalk"

// chalk.level:
// 0 = no colors (e.g., NO_COLOR env var, non-TTY)
// 1 = basic 16 colors
// 2 = 256 colors
// 3 = Truecolor (16M colors)

console.log(`Terminal color level: ${chalk.level}`)

// Force a specific level (useful for testing):
const chalkForced = new Chalk({ level: 1 })

// Respect NO_COLOR environment variable:
// chalk does this automatically — if process.env.NO_COLOR is set, chalk.level = 0

CLI output helpers

import chalk from "chalk"

// Status indicators:
const success = chalk.green("✓")
const failure = chalk.red("✗")
const warning = chalk.yellow("⚠")
const info = chalk.blue("ℹ")

console.log(`${success} Tests passed`)
console.log(`${failure} Build failed`)
console.log(`${warning} 3 deprecation warnings`)
console.log(`${info} Fetching package data...`)

// Progress output:
function printPackageHealth(name: string, score: number) {
  const color = score >= 80 ? chalk.green : score >= 60 ? chalk.yellow : chalk.red
  const bar = "█".repeat(Math.floor(score / 10)) + "░".repeat(10 - Math.floor(score / 10))

  console.log(
    chalk.bold(name.padEnd(30)) +
    color(bar) +
    " " +
    color.bold(`${score}/100`)
  )
}

printPackageHealth("react", 95)
printPackageHealth("lodash", 72)
printPackageHealth("moment", 45)

CommonJS note (chalk v4)

// chalk v5 is ESM-only — use v4 for CommonJS:
// package.json: "chalk": "^4"
const chalk = require("chalk")

// Or use kleur/colorette which support both

kleur

kleur — 2.5KB alternative with the same chain API:

Basic usage

import kleur from "kleur"

// Same API as chalk:
console.log(kleur.red("Error"))
console.log(kleur.green("Success"))
console.log(kleur.yellow().bold("Warning"))

// Chaining (slightly different — use function call for chaining):
console.log(kleur.red().bold("Red and bold"))
console.log(kleur.bgBlue().white().bold(" INFO "))

// Colors:
console.log(kleur.black("black"))
console.log(kleur.red("red"))
console.log(kleur.green("green"))
console.log(kleur.yellow("yellow"))
console.log(kleur.blue("blue"))
console.log(kleur.magenta("magenta"))
console.log(kleur.cyan("cyan"))
console.log(kleur.white("white"))
console.log(kleur.gray("gray"))

Template literal tag

import { red, green, bold, cyan } from "kleur"

// Named exports:
console.log(red("Error"))
console.log(green("Success"))
console.log(bold("Important"))
console.log(cyan("Info"))

// Compose:
const pkg = "react"
console.log(`${bold(pkg)}: ${green("healthy")} (score: ${cyan("95/100")})`)

NO_COLOR support

import kleur from "kleur"

// kleur respects NO_COLOR and FORCE_COLOR env vars:
// Set FORCE_COLOR=0 or NO_COLOR=1 to disable

// Check if colors are enabled:
kleur.enabled  // boolean

// Disable programmatically:
kleur.enabled = false
console.log(kleur.red("This prints without color now"))
kleur.enabled = true

colorette

colorette — 1.5KB, function-based, used by Vite and Rollup:

Basic usage

import { red, green, yellow, blue, bold, dim, reset } from "colorette"

// Function-based — no chaining:
console.log(red("Error: Package not found"))
console.log(green("Success: Data fetched"))
console.log(yellow("Warning: Rate limit approaching"))
console.log(blue("Info: Connecting to registry"))
console.log(bold("Important notice"))
console.log(dim("Secondary information"))

Compose manually

import { red, bold, bgBlue, white, dim } from "colorette"

// No chaining — compose by nesting:
console.log(bold(red("Error")))          // Red and bold
console.log(bgBlue(white("Info")))       // Blue bg, white text
console.log(bold(red("✗")) + " " + "Build failed")  // Mixed

// In practice, define helpers:
const error = (msg: string) => bold(red(`✗ ${msg}`))
const success = (msg: string) => bold(green(`✓ ${msg}`))
const warn = (msg: string) => bold(yellow(`⚠ ${msg}`))
const info = (msg: string) => blue(`ℹ ${msg}`)

console.log(error("Build failed"))
console.log(success("Tests passed"))
console.log(warn("3 deprecation warnings"))
console.log(info("Fetching data..."))

Checking color support

import { isColorSupported } from "colorette"

if (isColorSupported) {
  console.log("Terminal supports colors")
} else {
  console.log("No color support")
}

// colorette also respects:
// NO_COLOR env var — disables all colors
// FORCE_COLOR env var — forces colors even in non-TTY

Why Vite uses colorette

// colorette is used in Vite's build output:
// - 1.5KB — matters in build tools where deps add up
// - No auto-detection overhead — build tools know their context
// - ESM + CJS — works in both module systems
// - Functions, not chain — simpler tree-shaking

// The Vite output you see:
// ✓ 423 modules transformed.
// dist/index.html            0.41 kB
// dist/assets/index-abc.js   142.30 kB │ gzip: 46.80 kB

Feature Comparison

Featurechalkkleurcolorette
Bundle size~15KB~2.5KB~1.5KB
Chain API❌ Functions
ESM✅ v5
CJS✅ v4
256 colors
Truecolor (RGB)
Hex colors
Color detection✅ Auto⚠️ Manual✅ isColorSupported
NO_COLOR
FORCE_COLOR
Template literal tag
TypeScript

When to Use Each

Choose chalk if:

  • Building a CLI tool where rich styling matters (256 colors, Truecolor, hex)
  • You need automatic color level detection (chalk handles TTY, pipes, CI/CD)
  • Using template literal tags for complex styled output
  • Bundle size isn't a constraint

Choose kleur if:

  • You want a lighter chalk alternative with the same chain API
  • CommonJS + ESM compatibility in one package
  • Build tools or scripts where 12KB of savings matters
  • Basic 16 colors are sufficient (no need for Truecolor)

Choose colorette if:

  • Bundle size is critical (Vite, Rollup, other build tools)
  • You prefer function composition over chaining
  • ESM and CJS support with minimal overhead
  • Simple coloring — no complex multi-color chains

Consider Node.js util.styleText() if:

  • Node.js 22+ and no third-party dep is preferred
  • Only need basic styling (bold, red, green, etc.)
  • util.styleText(["red", "bold"], "Error") — built-in, no install needed

Migration Guide

From chalk v4 to chalk v5 (ESM migration)

Chalk v5 is ESM-only, which breaks CommonJS projects. Two paths forward:

// Option 1: Stay on chalk v4 (CommonJS compatible)
// package.json: "chalk": "^4"
const chalk = require("chalk")
console.log(chalk.red("Error"))

// Option 2: Migrate to ESM (chalk v5)
// package.json: "type": "module"
import chalk from "chalk"
console.log(chalk.red("Error"))

// Option 3: Switch to kleur (supports both CJS and ESM)
// package.json: "kleur": "latest"
import kleur from "kleur"           // ESM
// OR: const kleur = require("kleur")  // CJS — same package
console.log(kleur.red("Error"))

For CJS projects that can't migrate to ESM, kleur is the most direct chalk replacement. Its chain API (kleur.red().bold()) is nearly identical to chalk's (chalk.red.bold), with the difference that kleur uses function calls for chaining rather than property access.

Community Adoption in 2026

chalk leads by a wide margin at approximately 120 million weekly downloads — one of the most downloaded npm packages overall. This reflects its presence as a dependency in virtually every popular Node.js CLI tool and build system. ESLint, Prettier, Webpack, Jest, and hundreds of other tools depend on chalk directly. Even if you don't install chalk explicitly, it is present in almost every Node.js project's node_modules.

kleur and colorette each see several million weekly downloads, driven primarily by build tool authors who adopt them for their minimal footprint. colorette is used internally by Vite, Rollup, and esbuild's output formatting. kleur is used by tools like uvu (the test runner) and various lightweight CLI utilities from the lukeed ecosystem. For application developers choosing a coloring library directly, the choice between the three comes down to whether you need chalk's full feature set (Truecolor, template tags) or whether basic 16-color support is sufficient.

CI Environment Detection and Color Output Strategy

Terminal color libraries must detect whether their output will be read by a human or a machine and behave appropriately in both contexts.

Color level detection is the core mechanism. The ANSI color standards define four levels: 0 (no color, for pipes and CI), 1 (basic 16 colors), 2 (256-color ANSI), and 3 (16 million color RGB/TrueColor). Chalk detects the level automatically using has-flag, checking FORCE_COLOR, NO_COLOR, TERM, COLORTERM, and TERM_PROGRAM environment variables. A Chalk instance's detected level is exposed as chalk.level, which you can read to conditionally render color-dependent output.

The NO_COLOR standard (no-color.org) has been widely adopted since 2018: when NO_COLOR is set in the environment (to any value), programs must not output ANSI color escape codes. All three libraries respect this standard. This matters for: redirecting terminal output to files (node script.js > output.txt), capturing output in test assertions, piping through programs that don't support ANSI codes, and accessibility tools that read terminal output.

GitHub Actions injects FORCE_COLOR=1 by default in GitHub-hosted runners, enabling color output in CI logs. This produces readable, color-coded build output in the GitHub Actions log viewer. Kleur and colorette both respect FORCE_COLOR, so they produce colored output in GitHub Actions automatically. If you notice missing colors in other CI environments (GitLab CI, Bitbucket Pipelines), check whether the runner sets FORCE_COLOR or whether you need to set it manually in your CI configuration.

Testing color output requires care: tests that assert on console output content should strip ANSI escape codes before comparison. The strip-ansi package (a Chalk dependency) provides stripAnsi(string) for this purpose. A common mistake is to write tests that pass locally (with color disabled in the test environment) but fail in some CI environments where color is enabled by FORCE_COLOR, causing escape codes to appear in the asserted output string.

For library authors, consider making color output optional via a configuration option and respect the caller's choice. A library that forces color output (or suppresses it) regardless of environment reduces the composability of CLI tools built on top of it.

Performance Benchmarks for High-Volume CLI Output

For CLIs that produce thousands of styled output lines — log processors, build progress reporters, real-time monitoring tools — the performance difference between chalk, kleur, and colorette becomes relevant. colorette's function-based API has less overhead than chalk's Proxy-based chain API because it avoids the dynamic property lookup that chalk uses to build style chains. Kleur's chain API uses a similar Proxy mechanism to chalk for its fluent calls. In benchmarks measuring styled string generation throughput, colorette consistently leads by 15-30% over chalk, with kleur in between. For most CLI tools that produce human-readable output at interactive speeds (tens of lines per second), this difference is imperceptible. It becomes meaningful only when you're generating machine-scale output — millions of styled log lines, real-time terminal dashboards with frequent redraws, or CLI tools that run in tight loops processing streaming data. In those scenarios, pre-computing style strings outside the hot path (creating const errorStyle = red and reusing it) provides more benefit than switching libraries.

Node.js Built-in Alternative and When to Skip Dependencies

Node.js 22 introduced util.styleText(format, text) as a built-in alternative to third-party terminal color libraries. It supports the same basic modifiers — "red", "bold", "underline", "bgBlue", and combinations via array syntax like util.styleText(["red", "bold"], "Error"). For simple scripts, server-side logging, or CLI tools that target Node.js 22+ exclusively, util.styleText eliminates the need for any dependency. It respects the NO_COLOR environment variable and TTY detection automatically. The tradeoff is that it only supports basic 16-color ANSI formatting — no 256-color palette, no RGB/hex, and no template tag syntax. For any project that needs chalk's full feature set (Truecolor, hex colors, chaining complex styles), chalk or kleur remain necessary. But for the common case of color-coded log output in a Node.js 22+ server or utility script, the built-in is sufficient and reduces your dependency surface.

Methodology

Download data from npm registry (weekly average, February 2026). Feature comparison based on chalk v5.x, kleur v4.x, and colorette v2.x.

Compare developer tool and CLI packages on PkgPulse →

See also: Chalk vs picocolors and cac vs meow vs arg 2026, archiver vs adm-zip vs JSZip (2026).

The 2026 JavaScript Stack Cheatsheet

One PDF: the best package for every category (ORMs, bundlers, auth, testing, state management). Used by 500+ devs. Free, updated monthly.