CLI tool
pierrec/lz4 avatar
pierrec/lz4

pierrec lz4 is LZ4 in pure Go, with an assembly decoder

LZ4 compression and decompression in pure Go

971 stars161 forksGoBSD-3-Clause

At a glance

What is it?
The pierrec lz4 package gives Go programs a streaming interface to LZ4 data streams and low level functions for LZ4 blocks, and the implementation follows the reference C library. What is worth knowing is the shape of the API, since a reader and a writer plug into io.Pipe like any other Go streams, and that the speed comes from hand written assembly in the decoder rather than from the pure Go claim.
Who is it for?
pierrec lz4 fits a Go service that needs LZ4 framing without cgo, since the reader and writer are ordinary io interfaces and the frame format is interoperable with the reference implementation. It does not fit a project that needs the very fastest possible decoder, because the hot path relies on assembly, and it does not fit a team that wants a stable API across major versions, since the default branch is v4 and the module path carries the version suffix.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 12 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Frames for streams, blocks for the low level

The overview states the two things the package provides. There is a streaming interface to LZ4 data streams, and there are low level compress and uncompress functions for LZ4 blocks. The distinction is the one the format itself draws, where a frame is a self-describing container with a header, block sizes and optional checksums, and a block is just the compressed sequence with no framing around it. A stream is what you want for a file or a network connection, because the decoder can tell where each block ends and start on it, while a block is what you want when you are framing it yourself or when the data is already inside another container. The implementation is based on the reference C implementation, which is the important compatibility statement, because a Go implementation that produced a subtly different byte stream would be worse than useless.

The reader and writer are ordinary Go streams

The example in the documentation is the best explanation of the API, because it shows that the package does not ask you to learn a new model. A reader and a writer are created over an io.Pipe, and the data is copied between them with io.Copy, so the compression is invisible to the surrounding code:

go
// Compress and uncompress an input string.
s := "hello world"
r := strings.NewReader(s)

// The pipe will uncompress the data from the writer.
pr, pw := io.Pipe()
zw := lz4.NewWriter(pw)
zr := lz4.NewReader(pr)

The rest of the example runs the copy in a goroutine, closes the writer to flush the remaining data and then closes the pipe, and copies from the reader to standard output, producing the original string. The point about closing the writer is the one to remember, because until it is closed the final block is not flushed, and a truncated result is the classic symptom of forgetting it. For a service compressing a response, the same pattern appears with an HTTP body as the source and the response writer as the destination, and the same close rule applies.

A command line tool with format flags

The package ships a command line interface for compressing and decompressing LZ4 files, and it is installed separately from the library:

go
go install github.com/pierrec/lz4/cmd/lz4c@latest

The library itself is added with go get github.com/pierrec/lz4/v4, and the version suffix in the path is what makes the v4 line separate from the earlier ones. The usage output of the tool is short and tells you the format decisions that matter:

console
Usage of lz4c:
  -version
        print the program version

Under the compress subcommand there is a flag to enable a block checksum, a compression level flag where 0 is the fastest, a flag to disable the stream checksum, and a size flag for the block maximum size with the choices 64K, 256K, 1M and 4M and a default of 4M. The uncompress subcommand takes the same style of arguments. The block size is the setting to think about, since it trades compression ratio against memory use and against how much work is lost if a stream is truncated.

Checksums decide whether corruption is caught

The two checksum flags are the ones with real consequences, because a compressed format without integrity checking will happily return garbage for damaged input. The usage text describes a flag that enables the block checksum and a flag that disables the stream checksum, so the defaults are the other way round, which means the stream carries a checksum by default and individual blocks do not. For a long stream that is a sensible split, because a single checksum over the whole stream tells you that something is wrong but not where, while a per block checksum tells you the block and lets the decoder resynchronise, at the cost of a checksum per block. If you are writing data that will be moved between systems and could be corrupted in transit, choosing to enable the block checksum is a cheap decision and enabling the stream checksum as well is cheaper than finding out later.

The fast paths are written in assembly

The contributor notes explain where the speed comes from, and they are worth reading because they qualify the pure Go claim. The special thanks name an assembly implementation of the decoder, further assembly implementations of the decoder for amd64 and for arm64, work on optimizing the code, and work on the arm64 decoder together with the compressors, fuzzing and robustness testing. So the package is a Go implementation of the format, but its hot loops are not necessarily Go, and the contributions that carry the most weight are the ones that reach down to assembly. That is the normal shape of a compression library in any language, and it also explains the test files in the repository, where there are separate assembly related and portability related test targets, a fuzz directory, a robustness test and a race test. A library that is doing bit level work in assembly needs all of those.

The repository and the release state

The top level of the repository is the library plus a large test surface. The implementation is split into lz4.go, reader.go, writer.go, compressing_reader.go, options.go, state.go and their generated counterparts options_gen.go and state_gen.go, with an internal/ directory and a cmd/ directory holding the tool, plus a bench/ directory. The test files at the top level are the interesting part, with separate tests for the run length encoding path, for compatibility with the C implementation, for corpus and compression benchmarks, for random data, for robustness, for the silesia corpus, and for the race detector, alongside a fuzz/ directory, testdata/ and a fuzz_test.go. The module requires Go 1.22, the default branch is v4, and the releases are v4.1.33 published on 2026-10-02, v4.1.32 the same day and v4.1.31 on 2026-09-27. The last push was on 2026-10-11, the repository is not archived, and the licence is BSD-3-Clause. For a project at version 4.1 with that much churn, the practical advice is to pin the exact version you test against.

Editorial conclusion

pierrec lz4 fits a Go service that needs LZ4 framing without cgo, since the reader and writer are ordinary io interfaces and the frame format is interoperable with the reference implementation. It does not fit a project that needs the very fastest possible decoder, because the hot path relies on assembly, and it does not fit a team that wants a stable API across major versions, since the default branch is v4 and the module path carries the version suffix. Before you adopt it, read the command line usage, since the checksum defaults and the block size setting change the format of what you write, and note the release state, with v4.1.33 published on 2026-10-02 and the last push on 2026-10-11.

Frequently asked questions

What does the pierrec lz4 package provide?

A streaming interface to LZ4 data streams plus low level compress and uncompress functions for LZ4 blocks, implemented in Go and based on the reference C implementation, so the output is interoperable with other LZ4 tooling.

How do I use lz4 in a Go program?

Create a writer and a reader over an io.Pipe with lz4.NewWriter and lz4.NewReader, copy the data through them, and close the writer to flush the final block before closing the pipe.

Is there a command line tool for LZ4?

Yes, installed with go install github.com/pierrec/lz4/cmd/lz4c@latest. It has compress and uncompress subcommands, a version flag, a compression level flag where 0 is the fastest, flags for the block and stream checksums, and a block size option with the choices 64K, 256K, 1M and 4M and a default of 4M.

How is lz4 made fast if it is written in Go?

Through assembly implementations of the decoder, contributed for amd64 and for arm64, alongside optimisation work on the code. The contributor credits in the README name the people who wrote those assembly paths, as well as the work on the compressors and on fuzzing and robustness testing.

Is pierrec lz4 still updated?

The repository is not archived and the last push was on 2026-10-11, with v4.1.33 and v4.1.32 both published on 2026-10-02 and v4.1.31 on 2026-09-27. The default branch is v4, the module requires Go 1.22, and the licence is BSD-3-Clause.

Official sources

  1. Issues
  2. License: BSD-3-Clause
  3. pierrec/lz4 on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pierrec-lz4.svg)](https://hysenlabs.com/projects/pierrec-lz4)

Was this useful?