benchmarks.md
March 11, 2026 ยท View on GitHub
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
TerminaliTerm2v3.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 ') // fast and short
lib.red(lib.bold(lib.bgWhite(' ERROR '))) // slower and verbose
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')
styleText('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
- chalk@5.3.0 55.702.479 ops/sec
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
- styleText 579.832 ops/sec
Using 2 styles
Using only 2 styles, picocolors is already a bit slower, because applying multiple colours at once via 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
styleText(['red', 'bold'], 'foo')
...
+ ansis@3.5.0 60.468.181 ops/sec
- picocolors@1.1.1 58.777.183 ops/sec
- chalk@5.3.0 47.789.020 ops/sec
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
- styleText 561.290 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
styleText(['red', 'bold', 'bgWhite'], 'foo')
...
+ ansis@3.5.0 59.463.640 ops/sec
- chalk@5.3.0 42.166.783 ops/sec
- picocolors@1.1.1 32.434.017 ops/sec
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
- styleText 550.498 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
styleText(['red', 'bold', 'underline', 'bgWhite'], 'foo')
...
+ ansis@3.5.0 59.104.535 ops/sec
- chalk@5.3.0 36.147.547 ops/sec
- picocolors@1.1.1 17.581.709 ops/sec
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
- styleText 502.883 ops/sec
Nested styles
ansis.red(`red ${ansis.green(`green`)} red`)
chalk.red(`red ${chalk.green(`green`)} red`)
picocolors.red(`red ${picocolors.green(`green`)} red`)
styleText('red', `red ${styleText('green', 'green')} red`)
...
+ picocolors@1.1.1 15.146.177 ops/sec
colorette@2.0.20 13.722.200 ops/sec
kolorist@1.8.0 7.448.662 ops/sec
- ansis@3.5.0 7.325.956 ops/sec
- chalk@5.3.0 6.872.557 ops/sec
kleur@4.1.5 6.433.848 ops/sec
ansi-colors@4.1.3 3.921.601 ops/sec
colors@1.4.0 2.815.078 ops/sec
cli-color@2.0.4 1.093.307 ops/sec
colors-cli@1.0.33 304.693 ops/sec
- styleText 286.335 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
kolorist@1.8.0 847.110 ops/sec
- chalk@5.3.0 573.942 ops/sec
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
kolorist@1.8.0 2.548.564 ops/sec
- chalk@5.3.0 2.502.850 ops/sec
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
colorette@2.0.20 2.326.491 ops/sec
- chalk@5.3.0 2.129.106 ops/sec
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.