chalk vs kleur vs colorette: Terminal Color Libraries in Node.js (2026)
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@4for CommonJS orkleur/colorettefor 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
Download Trends
| Package | Weekly Downloads | Bundle Size | ESM | CJS | Chain 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
| Feature | chalk | kleur | colorette |
|---|---|---|---|
| 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
Methodology
Download data from npm registry (weekly average, February 2026). Feature comparison based on chalk v5.x, kleur v4.x, and colorette v2.x.