xdelta3: The VCDIFF Tool That Ships Multi-Gigabyte Game Patches in a Few Megabytes

2026-09-11

Every so often you need to hand someone a patch between two binary files — a 40 GB game update, a firmware image, an ISO, a database snapshot — and you don't have rsync at both ends. diff is useless. bsdiff loves the answer but wants 8× your file size in RAM and refuses to stream. Git's binary diffs live inside packfiles, not on disk.

The right tool has been sitting in your distro since Y2K: xdelta3, Josh MacDonald's implementation of VCDIFF (RFC 3284). It produces portable patch files, streams, handles files bigger than RAM, and is on the shortlist of tools ROM hackers, indie game studios, and update-server operators actually use in production.

The basic loop

# make a patch between two versions
xdelta3 -e -s v1.iso v2.iso v1_to_v2.vcdiff

# reconstruct v2 from v1 + patch
xdelta3 -d -s v1.iso v1_to_v2.vcdiff v2.reconstructed.iso

sha256sum v2.iso v2.reconstructed.iso  # identical

That's it. The -s flag names the source. Encoding is a single pass; decoding is fast because the format is optimized for the reader, not the writer.

The window-size gotcha nobody documents

The default source window is 64 MB. Feed xdelta3 a 4 GB source with the defaults and your patch will be almost as big as the target — it's only comparing against tiny slices at a time. Blow the window up to at least the size of the source:

xdelta3 -e -9 \
  -B $(stat -c %s v1.iso) \
  -W 16777216 \
  -s v1.iso v2.iso v1_to_v2.vcdiff

-B is the source window (RAM budget for the reference), -W is the target buffer, -9 asks for maximum effort. On a real 3.5 GB game update I benchmarked, the defaults gave a 2.9 GB patch; -B 4G -9 gave 41 MB.

Stream mode for pipes and tar

# patch a tarball on the fly
tar -c newtree/ | xdelta3 -e -c -s old.tar > delta.vcdiff

# apply, still streaming
xdelta3 -d -c -s old.tar delta.vcdiff | tar -x

Combined with mbuffer or pv, you can pipe deltas across an ssh link without ever materializing intermediates. This is how you ship a database dump diff without doubling your disk usage.

Secondary compression, if your data is compressible

xdelta3 -e -9 -S djw -s old.bin new.bin patch  # djw = built-in Huffman
xdelta3 -e -9 -S lzma -s old.bin new.bin patch  # if built with LZMA

VCDIFF already deduplicates repeated regions; secondary compression squeezes the residual literals. On text-heavy binaries (SQL dumps, structured logs) LZMA shaves another 40–60%.

Why not just rsync or bsdiff?

xdelta3 is the boring, portable, streamable, one-file answer. It has been shipping game patches since Half-Life 2 was new, and it will outlive most of the JavaScript runtime you're trying to save bytes on.

Key Takeaway: When you need a portable binary patch — not a network sync — reach for xdelta3 -e -9 -B $(stat -c %s src) -s src dst patch; just remember the default source window is 64 MB and quietly ruins every large-file benchmark you run without -B.

All newsletters