Skip to main content
Guides

Python 3.14's Built-in Zstandard (compression.zstd), Tested

By Mithun··7 min read
Quick Answer

Python 3.14 adds Zstandard to the standard library as compression.zstd (PEP 784) — no pip install. Use zstd.compress(data) / zstd.decompress(blob) for bytes, and ZstdFile or zstd.open() for files; levels run from fast (−5) to maximum (22), default 3. In my tests it compressed a 1.6 MB log file about 3.6× faster than gzip at a similar ratio, and can dial up to xz-level ratios. Needs Python 3.14+. Try it in our online Python compiler.

For years, reaching for Zstandard in Python meant a pip install (the zstandard or pyzstd package). Python 3.14 changes that: Zstd is now part of the standard library as compression.zstd (PEP 784), alongside a new compression namespace that also re-exports the classic gzip, bz2, lzma and zlib modules.

Zstd's reputation is a rare combination — near-gzip ratios at multiples of the speed, and a single dial that stretches all the way up to xz-class compression. So I installed Python 3.14.2 and actually measured it against the older codecs on a realistic 1.6 MB log file. Every number and code block below is from that run — including the cases where zstd *doesn't* win.

The basics: compress and decompress

The module-level API mirrors gzip: two functions for whole-buffer work. compress takes bytes and returns a compressed frame; decompress reverses it. There's nothing to install on 3.14 — it's in the standard library:

from compression import zstd
data = b"pyobfuscate.com " * 1000 # 16,000 bytes, very repetitive
blob = zstd.compress(data)
back = zstd.decompress(blob)
print(len(data), "->", len(blob)) # 16000 -> 34
print(back == data) # True
Whole-buffer round-trip — tested on Python 3.14.2

The public surface of the module is small and predictable: compress, decompress, the ZstdCompressor / ZstdDecompressor streaming classes, ZstdFile and open for files, a ZstdDict for trained dictionaries, plus CompressionParameter / DecompressionParameter enums for advanced tuning and COMPRESSION_LEVEL_DEFAULT (which is 3).

zstd vs gzip, bz2 and lzma: a real benchmark

I built a ~1.6 MB corpus of realistic JSON log lines (the kind of repetitive, structured data compression actually gets pointed at) and ran each codec on the identical bytes. These are measured results on Python 3.14.2 — sizes are deterministic; the timings are indicative of relative speed:

CodecSizeRatioCompressDecompress
zstd (default, level 3)128,962 B12.4×2.9 ms1.8 ms
gzip (level 6)114,809 B14.0×10.5 ms1.5 ms
bz2 (level 9)60,771 B26.4×192 ms21.8 ms
lzma / xz80,880 B19.8×331 ms7.1 ms

The honest read: zstd's headline is speed, not maximum ratio. At its default level it compressed this data in 2.9 ms — about 3.6× faster than gzip — for a comparable ratio, and it decompresses fast too. On *this* highly compressible data, bz2 and lzma actually squeezed smaller, but they paid 60–110× the compression time to do it. That trade-off is exactly zstd's pitch: near-instant compression you can afford to run on every request, log flush, or cache write.

Ratios are data-dependent. On repetitive JSON like this, the older codecs close much of zstd's usual ratio lead. On large, less-repetitive binary data, zstd's speed advantage typically comes with a ratio advantage too — always benchmark your own payload.

One codec, a huge speed/ratio dial

What makes zstd different from picking between gzip and xz is that a single codec spans the whole range. Levels run from −5 (fastest) through the default 3 up to 22 (maximum). Same corpus, four levels:

zstd levelSizeRatioCompress time
1 (fast)124,253 B12.9×2.2 ms
3 (default)128,962 B12.4×2.2 ms
9104,716 B15.3×16.8 ms
1979,554 B20.1×1,620 ms

At level 19 zstd reaches ~20× — matching xz's ratio on this data — but the time cost climbs steeply, so the high levels are for write-once/read-many data (release artifacts, backups) rather than hot paths. (Note the levels aren't perfectly monotonic on every input — low levels use a different internal strategy, which is why level 1 can edge level 3 here; the meaningful movement is at the top end.)

from compression import zstd
fast = zstd.compress(data, 1) # prioritise speed
small = zstd.compress(data, 19) # prioritise ratio
default = zstd.compress(data) # level 3
Pass a level as the second argument

Files, streaming, and tar archives

For files, compression.zstd gives you the same shape as gzip: an open() helper and a ZstdFile class. For data that arrives in chunks, ZstdCompressor lets you feed pieces and flush() at the end:

from compression import zstd
# whole-file helper, like gzip.open()
with zstd.open("logs.zst", "wt") as f:
f.write("hello\n")
# streaming: feed chunks, then flush
c = zstd.ZstdCompressor(level=9)
blob = c.compress(b"hello ") + c.compress(b"world") + c.flush()
print(zstd.decompress(blob) == b"hello world") # True
File helper and streaming compressor — tested

Python 3.14 also teaches tarfile the zstd modes, so you can create and read .tar.zst archives directly — no external tool required:

import tarfile
with tarfile.open("bundle.tar.zst", "w:zst") as tar:
tar.add("logs.zst")
with tarfile.open("bundle.tar.zst", "r:zst") as tar:
print(tar.getnames())
tarfile learned w:zst / r:zst in 3.14 — tested

When to use zstd (and when not to)

  • Reach for zstd when you compress often and latency matters: HTTP responses, log shipping, cache and session blobs, RPC payloads, or anything on a hot path. Default-level zstd is fast enough to run everywhere.
  • Turn the level up (15–22) for write-once/read-many data — release bundles, backups, model files — where you can spend CPU once to ship fewer bytes forever.
  • Stay with gzip when you need the most universal, zero-thought interop — every language and tool reads gzip, and for small payloads the difference is negligible.
  • Consider bz2 or lzma when maximum ratio is the only goal and compression time is irrelevant, as on the repetitive data above they still edged zstd on size.

Our marshal encryptor uses exactly this — it can wrap compiled Python bytecode with zstd on 3.14 for a smaller, version-locked loader. For a bytecode-specific comparison, see zlib vs zstd on Python bytecode.

Which Python version do I need?

compression.zstd ships in Python 3.14 (PEP 784), released October 2025. On 3.13 and earlier it doesn't exist — importing it raises ModuleNotFoundError — so there you install a third-party package such as zstandard or pyzstd, which wrap the same underlying libzstd with a different API.

try:
from compression import zstd # Python 3.14+
except ModuleNotFoundError:
import zstandard as zstd # pip install zstandard (3.13 and older)
Version-safe import

You can confirm what your interpreter has with our online Python compiler, which defaults to Python 3.14 — paste from compression import zstd; print(zstd.COMPRESSION_LEVEL_DEFAULT) and it prints 3.

Run these zstd examples in your browser

Our online Python compiler defaults to Python 3.14, so from compression import zstd works right away. Paste the snippets above and run them — no install.

Open the Python Compiler

Free tools mentioned here

Related guides

Frequently asked questions

What is compression.zstd in Python 3.14?

compression.zstd is a new standard-library module added in Python 3.14 (PEP 784) that provides Zstandard compression with no third-party install. It offers zstd.compress()/decompress() for bytes, ZstdFile and zstd.open() for files, streaming ZstdCompressor/ZstdDecompressor classes, and compression levels from -5 up to 22 (default 3).

Is zstd faster than gzip in Python?

In my test on a 1.6 MB log file, zstd at its default level compressed in about 2.9 ms versus gzip's 10.5 ms — roughly 3.6× faster — at a comparable ratio, and decompressed in about 1.8 ms. Speed is zstd's main advantage; exact numbers depend on your data, so benchmark your own payload.

Does zstd compress smaller than gzip, bz2, or lzma?

It depends on the data and level. At its default level zstd trades a little ratio for a lot of speed, so on highly repetitive data gzip, bz2, and lzma can compress smaller. Turned up to level 19–22, zstd reaches xz-class ratios (~20× in my test) — the point is that one codec spans the whole speed/ratio range.

How do I set the zstd compression level?

Pass the level as the second argument: zstd.compress(data, 19). Levels run from -5 (fastest) through the default 3 up to 22 (maximum ratio). Higher levels shrink the output but cost more CPU, so reserve the top levels for write-once/read-many data like release artifacts or backups.

How do I read and write .zst files in Python 3.14?

Use zstd.open("file.zst", "wb"/"rb"/"wt"/"rt") or the ZstdFile class, both of which behave like gzip.open. For chunked data use the streaming ZstdCompressor (compress() then flush()). Python 3.14 also added tarfile modes "w:zst" and "r:zst" for .tar.zst archives.

How do I use zstd on Python 3.13 or earlier?

compression.zstd only exists on Python 3.14+. On older versions, install a third-party package such as zstandard or pyzstd (pip install zstandard). They wrap the same libzstd library but expose a different API, so guard the import with try/except ModuleNotFoundError if your code must run on both.

Keep reading