The basics
What is an XZ file?
An XZ file is one file compressed with the xz program from XZ Utils. Like gzip and bzip2, xz compresses a single file and doesn't do folders. A folder is first bundled with tar, giving a .tar.xz or .txz file, which is the most common way you'll meet the format.
xz uses LZMA2, a refined version of the LZMA method from 7-Zip, wrapped in a container that adds checksums, an index and room for extra filters. It compresses noticeably better than gzip and decompresses far faster than bzip2, at the cost of slow compression. That suits software distribution: compressed once, downloaded and unpacked many times. The GNU project, many Linux distributions' source and package archives, and the Linux kernel's own downloads have used .tar.xz.
Older relatives you might meet: .lzma files are raw LZMA from the earlier LZMA Utils, without the checks or index, and 7z archives use the same LZMA and LZMA2 compression inside a different, multi-file archive format.
Anatomy
What's inside an XZ file
An XZ file is a stream: a header, one or more blocks of compressed data, an index listing the blocks, and a footer. Almost every part has its own CRC32, and every part is padded to a multiple of 4 bytes. Here is all of sample-text.txt.xz, 1,184 bytes; variable-length numbers use 7 bits per byte.
offset bytes part
0 FD 37 7A 58 5A 00 stream header magic
6 00 04 stream flags: check = CRC64
8 E6 D6 B4 46 CRC32 of the flags
12 02 block header size: (2+1) × 4 = 12
13 00 block flags: 1 filter, no sizes
14 21 01 16 filter LZMA2, 1 property byte: 8 MiB
17 00 00 00 header padding
20 74 2F E5 A3 CRC32 of the block header
24 E0 0A AC 04 5D 5D 00 1C … LZMA2 data, 1,125 bytes
1149 00 00 00 block padding to a multiple of 4
1152 97 AA 75 FE 48 E1 E8 CC CRC64 of the original data
1160 00 01 index: indicator, 1 record
1162 F9 08 · AD 15 block size 1,145; original 2,733
1166 00 00 · 8E 77 54 64 padding; CRC32 of the index
1172 B1 C4 67 FB stream footer: CRC32
1176 02 00 00 00 backward size: index is 12 bytes
1180 00 04 · 59 5A flags again; footer magic "YZ"
1184 end of file- 1
FD 37 7A 58 5A 00Stream header magic
FDkeeps it from being mistaken for the older.lzmaformat, and the zero byte at the end keeps it from looking like text. - 2
00 04Stream flags
The second byte names the integrity check:
01CRC32,04CRC64 (the default),0ASHA-256,00none. Insample-sha256.xzit's0A. - 3
02 00Block header
Its size in units of 4 bytes, then flags: one filter, and no compressed or uncompressed size stored. Single-threaded
xzleaves the sizes out; multi-threadedxzwrites them so blocks can be decompressed in parallel. - 4
21 01 16The filter chain
Filter
0x21is LZMA2, with one property byte:0x16means an 8 MiB dictionary, the size preset-6uses. A chain can hold up to four filters, for example a BCJ filter for x86 code before LZMA2. - 5
E0 0A AC 04 5DLZMA2 chunk header
E0starts a compressed chunk and resets the dictionary and settings,0A ACand04 5Dgive the chunk's sizes minus one (2,733 and 1,118 bytes), and5Dpacks the LZMA parameters lc=3, lp=0, pb=2. - 6
97 AA 75 FE 48 E1 E8 CCThe check
A CRC64 of the original 2,733 bytes, after the block. A decoder compares it after decompressing the block.
- 7
00 01 F9 08 AD 15The index
One record per block: its size in the file (1,145) and its original size (2,733). Tools read it from the end of the file to list sizes instantly, and to jump straight to a block.
- 8
02 00 00 00 · 59 5AStream footer
The index's size, so a reader starting from the end can find it, the flags again, and
YZ, the header magic's letters reversed.
Under the hood
How xz compresses: LZMA2, presets and memory
LZMA2 works like gzip's Deflate in outline: find repeated byte sequences and replace them with references back to an earlier copy. Two things make it compress better:
- A much larger window. Deflate looks back 32 KB. xz's dictionary is 8 MiB at the default level and 64 MiB at
-9, so a repeat far back in a large file still counts. - Range coding with adaptive probabilities instead of Huffman codes. It can spend a fraction of a bit on a very predictable symbol, where Huffman needs at least one.
| Preset | Dictionary | Memory to compress | Memory to decompress |
|---|---|---|---|
-0 | 256 KiB | 3 MiB | 1 MiB |
-6 (default) | 8 MiB | 94 MiB | 9 MiB |
-9 | 64 MiB | 674 MiB | 65 MiB |
The memory needed to decompress depends on the level used to compress, which matters on small devices. Levels -7 to -9 only help with files bigger than their dictionaries (8, 16 and 32 MiB, says the manual); on our 11.7 MB test, -9 saved 44 bytes over -6. Adding -e (extreme) tries harder at the same level for a slightly smaller file.
Filters prepare data before LZMA2. The BCJ filters (x86, ARM, ARM64, RISC-V and others) turn relative jump addresses in machine code into absolute ones, which repeat more, so executables compress better. The delta filter helps with some audio and image data.
Performance
Blocks, multi-threading and random access
A single-threaded xz writes one big block. With threads (-T0 uses every core), xz splits the input into blocks and compresses them in parallel; each block then stores its sizes in its header. Since XZ Utils 5.4, such files can also be decompressed in parallel, and since 5.6 multi-threaded mode is the default.
- Smaller blocks compress slightly worse, because each block starts with an empty dictionary. Our
sample-multi-block.xzuses 64 KiB blocks to show the structure; the default block size in threaded mode is three times the dictionary, 24 MiB at-6. - Random access: thanks to the index, a reader can jump to the block holding a given position without decompressing earlier blocks. Most tools don't offer this, but libraries can.
- Same input, different bytes: single-threaded and multi-threaded xz produce different files from the same input. Both decompress to the same data, but checksums of the
.xzfiles differ, which surprises people building reproducible packages.
Trade-offs
XZ vs gzip, bzip2, Zstandard and ZIP: size and speed
| Tool and level | Output size | Compression speed | Decompression speed |
|---|---|---|---|
| gzip -6 (default) | 20.2% | 25 MB/s | 160 MB/s |
| gzip -9 | 19.4% | 9 MB/s | 180 MB/s |
| bzip2 -9 (default) | 14.7% | 7 MB/s | 22 MB/s |
| xz -6 (default) | 15.6% | 1.2 MB/s | 66 MB/s |
| xz -9 | 15.6% | 1.2 MB/s | 73 MB/s |
| zstd -3 (default) | 21.4% | 120 MB/s | 440 MB/s |
| zstd -19 | 16.6% | 0.9 MB/s | 320 MB/s |
| ZIP, zip -6 (default) | 20.7% | 27 MB/s | 140 MB/s |
Output size is a percentage of the original. ZIP compresses each file separately, so it was measured on the folder, not the tar. Your numbers will differ with other data and hardware, but the pattern is typical:
- xz made a file about 23% smaller than gzip's default and unpacked about two and a half times slower, but it was by far the slowest to compress at the default level.
- bzip2 came out slightly smaller than xz on this text-heavy data, but decompressed three times slower.
- Zstandard at its default level was the fastest at everything, with gzip-like size. At
-19it got close to xz's size and decompressed five times faster than xz. That's why Arch Linux and Fedora switched their packages from xz to Zstandard. - gzip and ZIP sit in the middle: quick both ways, larger files, and readable everywhere.
Security
The 2024 XZ Utils backdoor (CVE-2024-3094)
On 29 March 2024, Andres Freund, a PostgreSQL developer at Microsoft, reported that XZ Utils versions 5.6.0 and 5.6.1 contained a deliberately hidden backdoor. It was rated CVSS 10.0, the maximum. He found it because SSH logins on a Debian test machine were using noticeably more CPU than before, and the memory checker Valgrind reported errors.
- Who: a contributor using the name Jia Tan, who had spent more than two years building trust in the project, with help from other accounts pressing the original maintainer, Lasse Collin, to share control.
- How it was hidden: the malicious code sat in two binary "test files" in the Git repository. A modified build script,
build-to-host.m4, was only in the release tarballs, not in Git, so reading the source on GitHub showed nothing wrong. - What it did: when built as a Debian or RPM package on x86-64 Linux with glibc, liblzma was altered to interfere with the OpenSSH server. Some distributions link
sshdto libsystemd, which loads liblzma. Someone holding the attacker's private key could then run commands on the server remotely. - Who got it: mainly development and rolling releases, such as Debian unstable, Fedora Rawhide and the Fedora 40 beta, openSUSE Tumbleweed and Kali Linux. Stable releases of the major distributions weren't affected. Distributions rolled back to 5.4.x within days, and the project released a clean 5.6.2 in May 2024.
What it means for .xz files
The backdoor was in the XZ Utils software, not in the file format. An .xz file can't carry it, and opening .xz files wasn't how it was triggered. If xz --version says 5.6.0 or 5.6.1, update through your distribution. The wider lesson is about the software supply chain: release tarballs can differ from the public source, and a single overworked maintainer is a target.
Troubleshooting
Common xz problems
File format not recognized: the file doesn't start with the xz magic. It may be an old.lzmafile (xz --format=lzma -dorunlzmahandles those), or something else with the wrong name.Memory usage limit reached: a memory limit is set (with--memlimitor theXZ_DEFAULTSvariable) below what the file needs.xz -lvv file.xzshows the memory needed; raise the limit for that file.Unexpected end of input: the file was cut short. With multi-block files,xz -dcstill outputs the complete blocks before the break.xzdeleted the original. Like gzip, xz replaces its input. Use-kto keep it.- Compression is very slow: that's xz at
-6or above. Use-T0for all cores, a lower level such as-3, or Zstandard if speed matters more than size. - A plain
.xzwon't open on Windows or Mac by double-click: use 7-Zip on Windows. On macOS,tar -xfhandles.tar.xz, but a single-file.xzneedsxzfrom Homebrew or an app such as Keka or The Unarchiver.
How to
How to open, create and convert an XZ file
- Linux:
unxz file.xz(orxz -d),xz -k fileto compress and keep the original,xzcatandxzlessto read without unpacking,xz -lto list sizes and ratio. For tarballs,tar -xf file.tar.xzandtar -cJf archive.tar.xz folder/. - macOS:
tar -xf file.tar.xzin Terminal works out of the box. For plain.xzfiles, install XZ Utils with Homebrew (brew install xz). - Windows: recent Windows 11 opens
.tar.xzand.txzarchives in File Explorer. Otherwise use 7-Zip, which reads and writes.xz. - Programming: Python's
lzmamodule, liblzma for C, Go and Rust libraries, and Apache Commons Compress with XZ for Java. - Convert:
xzcat file.tar.xz | gzip > file.tar.gz, orxzcat file.tar.xz | zstd -19 > file.tar.zst. The tar inside stays the same.
Decompression bombs
In our test, 1 GiB of zero bytes compressed to 156,316 bytes with xz -9, a ratio of about 6,900 to one. Code that decompresses uploaded .xz files must cap the output size and the memory it allows (liblzma has a memory limit setting).
Free downloads
Sample XZ files to download
Free sample XZ files for testing decompressors, libraries and upload checks. Each one passes xz -t and decompresses with Python's lzma module. All were made with XZ Utils 5.4.5, a version unaffected by the backdoor.
Browsers can't show this kind of file in a page. Download it to open it in the app it belongs to.
What's inside sample-text.txt.xz
A UTF-8 text file compressed with xz's defaults: preset -6, LZMA2 with an 8 MiB dictionary, a CRC64 check, one block. The anatomy above walks through every structure in it.
Stream header
FD 37 7A 58 5A 00, then flags naming CRC64 as the check.One block
A 12-byte block header naming LZMA2 with an 8 MiB dictionary, then 1,125 bytes of LZMA2 data.
The check
CRC64
0xCCE8E148FE75AA97of the original text, written little-endian after the block.Index and footer
12 bytes of index, then a 12-byte footer ending in
YZ.xz -lvv sample-text.txt.xzprints all of this.No name, no date
XZ stores neither. The output name comes from dropping
.xz.Overhead on small files
The containers add 59 bytes around the LZMA2 data. On a 2,733-byte text that's noticeable; on a 100 MB file it's nothing.
All sample XZ files
Text file, default settings
sample-text.txt.xz · 1.2 KB (1,184 bytes)
A UTF-8 text file with accented letters, Greek, Japanese and an emoji, compressed with
xz -6 -T1: one stream, one block, CRC64.- Basic decompression tests
- Learning the structure with `xz -lvv`
Project folder as .tar.xz
sample-project.tar.xz · 3.7 KB (3,760 bytes)
A small project folder (README, CSV, JSON, a PNG and an executable script) in a ustar archive, compressed with
xz -6. The same files as the .tar.gz and .tar.bz2 samples.- Testing `.tar.xz` extraction
- Comparing sizes with the .tar.gz and .tar.bz2 versions
Six blocks, sizes in headers
sample-multi-block.xz · 33.4 KB (34,224 bytes)
A 393,211-byte log of fictional weather readings compressed with two threads and
--block-size=65536: six blocks, each with its sizes in the block header, as multi-threaded xz writes them.- Testing multi-threaded decompression
- Index parsing and random access
SHA-256 integrity check
sample-sha256.xz · 684 bytes
A short text compressed with
--check=sha256, so stream flags are00 0Aand each block ends with a 32-byte SHA-256 hash. Decoders aren't required to support this check.- Checking a decoder supports every check type
- Testing what happens when it doesn't
Ways to test with them
- Check types:
sample-sha256.xzuses SHA-256. The specification only requires decoders to support CRC32 and no check, so minimal decoders may refuse this file; they should say so clearly rather than skip the check silently. - Threaded decoding:
xz -dc -T0 sample-multi-block.xzcan use several threads because the block headers store sizes;xz -lvvshowscuunder Flags for each block. - Integrity: flip a byte in the middle of
sample-multi-block.xz.xz -tshould name a corrupt block, and the other blocks still decompress. - Size comparison: the same project is 3,760 bytes here, 3,997 as .tar.bz2 and 4,273 as .tar.gz.
Free to use for testing, teaching and demos, commercially or not, with no attribution needed. A link back to this page is always appreciated.
Put it online
Have an XZ file? Give it a link.
Drop an .xz or .tar.xz file on 99helpers and it gets its own download link, so you can share a release or a data set without attachment limits. Anyone with the link downloads the file exactly as you uploaded it.
Questions
XZ files, frequently asked
What is an .xz file?
A single file compressed with xz, using LZMA2. If the name ends in .tar.xz or .txz, it's a whole folder: a tar archive compressed with xz.
How do I open an .xz file?
On Linux, unxz file.xz, or tar -xf file.tar.xz for an archive. On Windows, 7-Zip or, for .tar.xz, recent Windows 11 File Explorer. On macOS, tar -xf in Terminal for .tar.xz.
Is xz better than gzip?
It makes smaller files: about 23% smaller than gzip's default in our test. It's much slower to compress and somewhat slower to decompress, so gzip is still the better choice when speed matters.
Is it safe to use xz after the backdoor?
Yes. Only XZ Utils 5.6.0 and 5.6.1 were affected, and distributions removed them within days in March 2024. Check with xz --version. The .xz file format itself was never the problem.
What's the difference between .xz and .7z?
Both can use LZMA2 compression. .xz compresses one file and relies on tar for folders; .7z is a full archive format with folders, encryption and solid compression built in.
What's the difference between .tar.xz and .txz?
None. .txz is the short form. unxz turns either into a .tar file.
Why does xz take so long to compress?
LZMA2 searches a large dictionary for the best matches. On our test machine the default level compressed at about 1.2 MB/s on one core. Use -T0 to use all cores, or a lower level.
Should I use xz or Zstandard?
For the smallest files when you compress once and unpack rarely, xz. For speed, or when files are unpacked often, Zstandard: in our test zstd -19 was within about 7% of xz's size and decompressed about five times faster.
Related formats
Other file types explained
Keep going
Related
Sources
- Tukaani Project: The .xz File Format specification
- xz(1) manual page
- Openwall oss-security: backdoor in upstream xz/liblzma (29 March 2024)
- Tukaani Project: XZ Utils backdoor
- Rapid7: Backdoored XZ Utils (CVE-2024-3094)
- Wikipedia: XZ Utils backdoor
Last reviewed 27 October 2026.