zlib level 6 reached 102.7 MB/s and an 110.28x ratio
In this article
Compressing a 6,642,000-byte input with Python's standard library produced 102.7 MB/s and an 110.28x ratio for zlib-6, while lzma reached a 1030.73x ratio at 11.8 MB/s. The compression ratio should not be trusted too literally.
I made the input by repeating my site's build script 400 times. It therefore contained the same strings over and over. The redundancy was much stronger than in real files, so choosing the corpus was a failure. The more spectacular the number, the more I should have questioned how the input was made.
The comparison is not meaningless. Every algorithm processed the same input with the same ARM64 Python 3.12.10 build, so the speed ordering is still observable. The zlib-level differences, bz2's slowness, and lzma's ratio are measured comparisons on my Surface Pro.
The data was captured at 2026-06-13T20:17:52. This one run from June 13, 2026 is the entire log; it is not an average of measurements repeated on different days.
Feeding the same bytes to the standard library
I called Python's zlib, bz2, and lzma directly and compressed the same bytes three times each. The input was text; I did not mix in images or already compressed files. That is also the weak point of the test, because it is far from a real folder.
import bz2
import lzma
import zlib
cases = {
"zlib-1": lambda data: zlib.compress(data, 1),
"zlib-6": lambda data: zlib.compress(data, 6),
"zlib-9": lambda data: zlib.compress(data, 9),
"bz2-9": lambda data: bz2.compress(data, compresslevel=9),
"lzma": lambda data: lzma.compress(data),
}
I recorded the three run times, median, output bytes, input-to-output ratio, and MB/s, using the table values as measured. Recalculation and rounding differences make a log harder to review later.
The input was 6,642,000 bytes. Because it was an artificial 400-repeat corpus, it was unusually friendly to compression. Ordinary JSON logs can contain repetition too, but not a single identical pattern to this extent. The absolute ratios should therefore be treated as rough indicators.
The speed and size table
Here are the three runs_ms values as recorded. The median looks tidy, but even zlib-1 ranged from 45.1ms to 81.7ms, so one run would be unsafe.
| Method | runs_ms (three runs) | median_ms | MB/s | out_bytes | ratio |
|---|---|---|---|---|---|
| zlib-1 | 63.31 / 45.1 / 81.7 | 63.31 | 104.9 | 829435 | 8.01 |
| zlib-6 | 64.68 / 52.84 / 71.7 | 64.68 | 102.7 | 60230 | 110.28 |
| zlib-9 | 101.81 / 109.57 / 144.55 | 109.57 | 60.6 | 54538 | 121.79 |
| bz2-9 | 1014.56 / 1151.17 / 1019.37 | 1019.37 | 6.5 | 77144 | 86.1 |
| lzma | 624.62 / 562.59 / 564.61 | 564.61 | 11.8 | 6444 | 1030.73 |
input_bytes was 6,642,000 bytes, and lzma reduced out_bytes to 6,444 bytes. A 1030.73x ratio is striking, but it is too early to celebrate. It does not mean real data will shrink by more than 1,000x. Repeating the same build script means that, after the dictionary is established, the compressor can refer to the same material again and again. A real folder may include PNG, WebP, zip, SQLite, and nearly random log fragments, which would destroy the ratios in this table.
What differed from my expectation
The zlib-1 versus zlib-6 result was the first surprise. zlib-1 ran at 104.9 MB/s and zlib-6 at 102.7 MB/s, almost the same speed. Their ratios, however, jumped from 8.01x to 110.28x. In this table, there seems to be little reason to choose level 1.
I initially expected lowering the level to produce a clear speed gain. I imagined the usual tradeoff: give up some compression to get speed. On this input, the speed benefit was too small. The output was 829,435 bytes versus 60,230 bytes, but median_ms was 63.31ms versus 64.68ms.
zlib-9 was also interesting. Speed fell to 60.6 MB/s, while the ratio rose only slightly from zlib-6's 110.28x to 121.79x, reducing output from 60,230 to 54,538 bytes. The extra result was small compared with the additional wait. It may make sense when storage is the priority, but for temporarily packing build artifacts or logs I would personally stop at level 6.
bz2-9 was particularly difficult: 6.5 MB/s is an order of magnitude below zlib-6's 102.7 MB/s, while its 86.1x ratio does not approach lzma's 1030.73x. It was hard to find a reason to wait. I tried the older format, but for this input it gave little return for the time.
The failure in this run
The failure was making the test data too easy. The lzma row makes the reason obvious, and I wish I had noticed before measuring.
Concatenating my site's build script 400 times made it easy to compare all methods with the same byte count. As a compression corpus, it was too simple. The 6,444-byte lzma output and 1030.73x ratio look more like the consequence of a contrived input than the algorithm's general ability.
Before noticing this, I was about to write only that “lzma is overwhelmingly strong.” That was dangerous: the measurement ran and produced no error. The lesson is that spectacular numbers require more scrutiny of the input.
The absolute compression ratio is not safe to generalize. As a relative comparison on this same input, the speed ordering is still useful: zlib was fast, bz2 slow, and lzma favored compression ratio. That level of conclusion seems supported by this log.
How I would choose them
For my own use I would start with zlib-6. On this input it ran at 102.7 MB/s and reduced out_bytes to 60,230 bytes. zlib-1 ran at 104.9 MB/s, so it was only slightly faster but produced 829,435 bytes. The small speed difference and large output difference make level 1 hard to justify for small archive jobs.
I would reserve zlib-9 for cases where the compressed size needs to be reduced a little further: wait 109.57ms for 54,538 bytes, or 64.68ms for 60,230 bytes. From these numbers alone, the latter is normally enough.
I would use lzma when a single artifact must be as small as possible and speed can be sacrificed. At 11.8 MB/s it is too heavy for every build. In this range bz2 is difficult to choose: 6.5 MB/s and an 86.1x ratio make zlib-6 or lzma more attractive.
I plan to repeat the test with a folder containing images, real JSON logs, and already compressed files. This log is not evidence that the ratios can be taken literally; it records how an overly convenient corpus can create a result that looks stronger than it is.