Skip to content
JSONCraft

Performance

JSON compression: measure gzip and Brotli on your data

Run a downloadable Node benchmark, compare UTF-8 byte sizes and decode time, and decide whether a binary format is worth testing.

Before changing an API format, separate three costs: bytes transferred, compression work at the producer, and decompression plus parsing at the consumer. A smaller file can still be a worse choice if it increases latency or complicates compatibility.

A benchmark you can reproduce

Download compression-benchmark.mjs. It uses only Node built-ins. Run with Node 22 or later:

node compression-benchmark.mjs
node compression-benchmark.mjs ./sample.json

Without an argument it generates 1,000 records with id, name, city: "Málaga" and active. This deliberately repetitive dataset is a controlled example, not a representative sample of every API. With an argument, it reads your local JSON file; it makes no network request.

The script compares pretty JSON, compact JSON, gzip level 6 and Brotli quality 4. It checks that both compressed forms decompress to the exact compact input. It prints the Node and compression-library versions alongside the results so you can record the environment.

Scroll horizontally to see all columns.

Result What it measures
bytes.pretty / bytes.compact UTF-8 bytes, with / without formatting whitespace
bytes.gzip6 / bytes.brotli4 Compressed compact JSON, including format overhead
meanMsPerOperation Mean decode-and-parse time across 1,000 iterations after 100 warm-ups
roundTrip Exact decompressed byte equality

Run on at least a small message and a realistic response from your application. Use synthetic or redacted data. Repeat the run and compare variation. This script is synchronous and intended for local experiments, not request handling in a production server. It does not measure network latency, peak memory or concurrent throughput.

Count bytes, not JavaScript characters

const text = '{"city":"Málaga"}';
console.log(text.length);                  // 17 UTF-16 code units
console.log(Buffer.byteLength(text));      // 18 UTF-8 bytes

The formatter can remove whitespace, but minification is different from gzip or Brotli. A compact document still repeats property names, which a compressor may exploit. A tiny response may grow once compression headers are included.

When to consider MessagePack or CBOR

These formats offer binary representations and types beyond JSON’s portable subset. They need compatible encoders and decoders on both sides. They are worth testing when binary values, type fidelity or transport constraints matter; neither has a universal size or parsing-speed advantage.

Compare equivalent data, compression settings, encoder versions and the whole encode/decode path. A raw binary size should not be compared with gzipped JSON as if both used the same transport settings. Protocol Buffers adds a schema-management decision; it is not a drop-in switch for an arbitrary public JSON endpoint.

Shipping a decision

Check the real response’s Content-Encoding and Vary headers. Compression is not automatically enabled in every server or CDN configuration. Preserve a readable fallback where consumers require JSON. On ingestion, cap both received and decompressed bytes: a small compressed request can expand substantially.

Read the Node compression API, MessagePack specification and CBOR RFC 8949. For input too large to materialize, see streaming JSON: compressing bytes on disk does not remove the memory cost after decompression.

Related tools

Frequently asked questions

Does gzip always make JSON smaller?

No. Compression has overhead, especially for small or already compressed data. Compare actual encoded byte sizes.

Is the reported timing a median?

No. The example reports mean milliseconds per operation after a warm-up. Repeat runs on the target hardware; it is not an HTTP latency benchmark.

By