Skip to content

Benchmarks

Compression and decompression speed and compression ratio of zstd, gzip, brotli and LZ4 in comprs, for 84 KB of JSON gzip compression speed at level 6 of comprs, node:zlib, pako and fflate, for 84 KB of JSON

From the run below, on x86-64 Linux with Node.js 24:

  • zstd is faster than gzip and brotli in comprs, for compression and decompression alike, with a better ratio than gzip. LZ4 compresses faster still on four of the six inputs, at a lower ratio, but decompresses faster than zstd only for 150 bytes of text and 84 KB of JSON. Against the zstd of node:zlib at the same level, comprs compresses 1.1–2.7 times and decompresses 1.4–3.6 times as fast, to the same size.
  • gzip decompression is 3.5–16 times as fast as pako and 1.0–2.0 times as fast as node:zlib; fflate is faster on incompressible data and on 150 bytes. deflate (zlib) decompression is 1.5–5 times as fast as pako, and 0.8–1.3 times as fast as node:zlib.
  • gzip and deflate compression of 84 KB of JSON is 1.5 times as fast as node:zlib and 4.2–4.7 times as fast as pako, at the same ratio within 1%. comprs compresses with zlib-rs, which follows the algorithms of zlib-ng: on extremely repetitive input, such as one sentence repeated, it trades ratio for speed (82:1 against 122:1 for zlib), so the speeds on those inputs are not like for like. For 150 bytes, node:zlib is faster.
  • brotli comes from libbrotli, the C library of node:zlib: it compresses to the same size at about the same speed, and decompresses up to 1.5 times as fast.
  • Node.js streams of comprs are 3.7–7.9 times as fast as those of node:zlib for 1 MB in 16 KB chunks.
  • These numbers are from the native addon; the WebAssembly build was not measured.

Measured on 2026-10-25 with comprs 2.3.0 (fb6a968), Node.js v24.21.0, pako 3.0.2 and fflate 0.8.3, on AMD EPYC 7763 64-Core Processor × 4 (linux/x64), in this run of the Bench Report workflow, on a GitHub-hosted runner (ubuntu24, image 20261023.334.3). Settings, the same for every library in a table: gzip level 6 · deflate level 6 · brotli quality 6, lgwin 22 · brotli quality 11, lgwin 22 · zstd level 3 · streams: gzip level 6, zstd level 3 · cross-algorithm: each format’s default settings (lz4 has no levels). Speeds are MB/s of uncompressed data (1 MB = 1,000,000 bytes), from the median time of a call. Every library decompresses the output of comprs, so that only the decoders differ, except in the cross-algorithm table, where each format decompresses its own. The compression ratio is the input size divided by the output size.

Cross-algorithm comparison: zstd vs gzip vs brotli vs lz4 (comprs only, default settings)

Compression (MB/s of uncompressed data, higher is better)

Input zstd gzip brotli lz4
text 150B 56.5 13.2 15.5 85.5
JSON 84KB 583 233 76.9 1,122
text 45KB 3,535 1,715 1,602 3,194
random 10KB 932 80.8 108 1,672
random 1MB 3,811 49.9 381 2,891
patterned 1MB 6,274 2,866 1,331 3,703

Decompression (MB/s of uncompressed data, higher is better)

Input zstd gzip brotli lz4
text 150B 103 59.7 46.6 111
JSON 84KB 1,757 1,395 889 2,374
text 45KB 8,026 2,992 1,034 1,772
random 10KB 4,822 2,233 3,108 2,796
random 1MB 13,711 4,000 6,864 4,386
patterned 1MB 17,150 4,398 1,136 1,861

Compression ratio (input size ÷ output size, higher is better)

Input zstd gzip brotli lz4
text 150B 4.84 3.95 5.56 2.78
JSON 84KB 9.25 7.54 10.4 4.60
text 45KB 285 81.8 286 105
random 10KB 1.00 1.00 1.00 1.00
random 1MB 1.00 1.00 1.00 1.00
patterned 1MB 2,755 128 3,846 199
gzip, level 6: comprs vs pako vs fflate vs node:zlib

Compression (MB/s of uncompressed data, higher is better)

Input comprs pako fflate node:zlib
text 150B 12.4 2.16 6.98 19.7
JSON 84KB 231 49.0 36.3 152
text 45KB 1,709 84.5 83.7 294
random 10KB 81.2 32.5 36.5 97.9
random 1MB 49.7 20.4 36.0 48.7
patterned 1MB 2,834 77.7 83.2 291

Decompression (MB/s of uncompressed data, higher is better)

Input comprs pako fflate node:zlib
text 150B 59.2 17.1 189 59.0
JSON 84KB 1,385 191 375 943
text 45KB 3,001 242 803 1,522
random 10KB 2,184 300 6,698 1,845
random 1MB 3,987 365 9,362 2,282
patterned 1MB 4,265 265 883 2,286

Compression ratio (input size ÷ output size, higher is better)

Input comprs pako fflate node:zlib
text 150B 3.95 3.95 4.05 3.95
JSON 84KB 7.54 7.58 8.09 7.58
text 45KB 81.8 122 122 122
random 10KB 1.00 1.00 1.00 1.00
random 1MB 1.00 1.00 1.00 1.00
patterned 1MB 128 237 237 237
deflate, level 6: comprs vs pako vs fflate vs node:zlib

Compression (MB/s of uncompressed data, higher is better)

Input comprs pako fflate node:zlib
text 150B 13.1 2.20 7.48 20.7
JSON 84KB 236 56.7 41.2 158
text 45KB 2,022 113 107 324
random 10KB 83.7 38.2 40.6 99.2
random 1MB 50.0 22.0 40.7 49.5
patterned 1MB 3,708 96.2 111 332

Decompression (MB/s of uncompressed data, higher is better)

Input comprs pako fflate node:zlib
text 150B 77.6 17.4 2.19 65.1
JSON 84KB 1,521 365 259 1,194
text 45KB 3,284 608 358 2,211
random 10KB 3,007 952 2,527 3,431
random 1MB 6,015 4,064 3,256 5,018
patterned 1MB 4,066 790 664 5,096

Compression ratio (input size ÷ output size, higher is better)

Input comprs pako fflate node:zlib
text 150B 7.50 7.50 7.89 7.50
JSON 84KB 7.55 7.59 8.10 7.59
text 45KB 84.5 128 129 128
random 10KB 1.00 1.00 1.00 1.00
random 1MB 1.00 1.00 1.00 1.00
patterned 1MB 128 238 238 238
brotli, quality 6, lgwin 22: comprs vs node:zlib

Compression (MB/s of uncompressed data, higher is better)

Input comprs node:zlib
text 150B 15.4 12.4
JSON 84KB 77.6 76.6
text 45KB 1,576 1,462
random 10KB 108 101
random 1MB 423 415
patterned 1MB 1,335 1,328

Decompression (MB/s of uncompressed data, higher is better)

Input comprs node:zlib
text 150B 45.9 37.3
JSON 84KB 908 753
text 45KB 1,041 808
random 10KB 3,081 2,743
random 1MB 6,844 4,540
patterned 1MB 1,131 1,124

Compression ratio (input size ÷ output size, higher is better)

Input comprs node:zlib
text 150B 5.56 5.56
JSON 84KB 10.4 10.4
text 45KB 286 286
random 10KB 1.00 1.00
random 1MB 1.00 1.00
patterned 1MB 3,846 3,846
brotli, quality 11, lgwin 22: comprs vs node:zlib

Compression (MB/s of uncompressed data, higher is better)

Input comprs node:zlib
JSON 84KB 0.74 0.75
patterned 10KB 13.1 13.6

Decompression (MB/s of uncompressed data, higher is better)

Input comprs node:zlib
JSON 84KB 885 733
patterned 10KB 693 669

Compression ratio (input size ÷ output size, higher is better)

Input comprs node:zlib
JSON 84KB 13.5 13.5
patterned 10KB 46.1 46.1
zstd, level 3: comprs vs node:zlib

Compression (MB/s of uncompressed data, higher is better)

Input comprs node:zlib
text 150B 56.5 20.3
JSON 84KB 596 522
text 45KB 3,519 1,916
random 10KB 917 555
random 1MB 3,825 2,046
patterned 1MB 6,270 1,834

Decompression (MB/s of uncompressed data, higher is better)

Input comprs node:zlib
text 150B 103 36.5
JSON 84KB 1,757 1,280
text 45KB 7,917 2,952
random 10KB 4,753 2,124
random 1MB 14,178 4,506
patterned 1MB 17,091 4,801

Compression ratio (input size ÷ output size, higher is better)

Input comprs node:zlib
text 150B 4.84 4.84
JSON 84KB 9.25 9.25
text 45KB 285 285
random 10KB 1.00 1.00
random 1MB 1.00 1.00
patterned 1MB 2,755 2,755
Node.js streams: comprs vs node:zlib

Transform streams (MB/s of uncompressed data, higher is better)

Stream Input comprs node:zlib
gzip compress, level 6 patterned 1MB in 16KB chunks 1,175 166
gzip decompress, level 6 patterned 1MB in 16KB chunks 1,710 329
gzip round-trip, level 6 patterned 1MB in 16KB chunks 762 108
zstd compress, level 3 patterned 1MB in 16KB chunks 1,646 388
zstd decompress, level 3 patterned 1MB in 16KB chunks 2,925 425
zstd round-trip, level 3 patterned 1MB in 16KB chunks 837 289

The Bench Report workflow runs scripts/bench-report.mjs on a GitHub-hosted runner, with every library at the same settings, and writes the tables and the charts from that one run, with the versions, the machine and the settings above the tables. Run the benchmarks yourself with pnpm run bench in a clone of the repository; numbers vary by machine and data. CodSpeed tracks the Rust benchmarks on the pull requests that change Rust code, to catch performance regressions.