rust-brotli gives you Brotli without the C dependency and without std
Brotli compressor and decompressor written in rust that optionally avoids the stdlib
At a glance
- What is it?
- Dropbox's rust-brotli is a Rust implementation of the Brotli compressor with an interface that can avoid the standard library, a pluggable allocator and a C FFI crate. It fits embedded and kernel-adjacent work where linking a C library is the problem, and it is the wrong choice if you want the reference C encoder's output byte for byte.
- Who is it for?
- Choose rust-brotli when your target has no stable standard library, when you need to hand the encoder a custom allocator, or when you want Brotli in a build that must not link the C library, and stay on the reference C implementation when byte identical output against existing Brotli streams matters.
- 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 51 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem is not compression, it is the dependency on std
Brotli itself is not the difficult part of this project. The difficult part is where you can run it. The crate description spells out the intent: a Brotli compressor and decompressor with an interface that avoids the Rust standard library, which the description says makes it suitable for embedded devices and kernels, with a pluggable allocator so the standard library allocator may be employed, a default build that also includes a stdlib allocator and stream interface, and the note that all included code is safe.
That is a coherent target audience. Kernel modules, firmware images, hypervisor agents and other code that runs before a hosted runtime exists cannot link a C library casually, and many Rust codebases in that space cannot afford the standard library's allocator and panic machinery. For those teams the interesting property is not compression ratio. It is that a Brotli codec can exist inside a firmware image at all.
The topics attached to the repository list brotli, compression, rust, safe and no-std vocabulary, and the crate carries the no-std category in its manifest. The homepage points to a Dropbox engineering article on syncing less to move faster, so the tool is used in the context of a sync service, not as a general purpose CLI to a compress files by hand, though it does ship one.
The trade-off should be stated plainly at the start. This is a reimplementation with a different deployment story, and the notes on versions 8.0.0 and 9.0.0 show the authors correcting divergences from the reference Brotli specification, including LZ77 context seeding behaviour with custom dictionaries. A codec that had to be fixed to comply with the specification is a codec whose edge cases were, at some point, not the same as the C library.
Crate layout, the two binaries and the FFI crate
The repository splits into a main crate plus a C facing crate in the c directory. The manifest defines two binaries, brotli and catbrotli, both with doc set to false and autobins disabled at the package level. The dependency set is deliberately tiny: alloc-no-stdlib for the allocator traits, alloc-stdlib as an optional companion, and brotli-decompressor pinned to a narrow range with default features off. A sha2 dependency sits behind an optional flag.
The allocator crates are the load bearing part. The manifest comment explains why the version ranges are narrow: alloc-no-stdlib's Allocator and SliceWrapper traits are part of the public API of this crate and of brotli-decompressor, so the ranges must not span a major, otherwise the resolver can split the trait identity between the two crates and an allocator from one no longer satisfies the other's bound. That is a subtle and specific failure mode, and it is documented in the file itself rather than left to be discovered.
The FFI is not part of the default build. The 5.0.0 notes say the FFI is no longer active by default to avoid ODR issues if multiple versions of brotli are included in several dependent crates, and 4.0.0 pinned a decompressor that can disable the FFI with the ffi-api flag to help avoid symbol conflicts with other Brotli libraries. The 3.0.0 notes describe it as a fully compatible FFI for drop in compatibility with the Google Brotli binaries, with custom allocators supported. So the crate offers both worlds, but you opt into the C surface deliberately.
The examples directory holds compress.rs and decompress.rs, and the research and testdata directories sit alongside a justfile that drives the build, so the project has a developer workflow even though the published artefact is a library.
Building it: the justfile is the closest thing to install docs
There is no installation section in the README, because there is nothing to install. rust-brotli is a library crate plus two binaries, consumed as a Cargo dependency, and the build recipes live in the justfile at the repository root. The default target is simply a listing:
@_default:
just --list --unsortedThe main build recipe compiles the whole workspace with warnings denied, which tells you the project treats warnings as errors in CI:
build-brotli:
RUSTFLAGS='-D warnings' cargo build --workspace --all-targets --bins --tests --lib --benches --examplesSIMD is a separate recipe because it needs a nightly toolchain, and the FFI crate gets its own recipe plus a Makefile in the c directory:
build-simd:
RUSTFLAGS='-D warnings' cargo +nightly build --features simdbuild-ffi:
RUSTFLAGS='-D warnings' cargo build --features ffi-api
RUSTFLAGS='-D warnings' cargo build --workspace --all-targets --bins --tests --lib --benches --examples --manifest-path c/Cargo.toml
cd c && makeThe build-ffi recipe carries an honest comment: the c/Cargo.toml does not depend on the unpublished main crate, so its build never actually gets tested, and for now the original make file is used for building and testing the FFI crate. That comment is worth reading before you rely on that path.
For a first real use as a library, the practical sequence is: add brotli to your Cargo.toml, pick your features, and compress or decompress through the stream interface. The manifest requires edition 2015 and rust-version 1.59.0, so the minimum supported Rust version is not a recent one, which is consistent with a crate that targets constrained environments.
Custom dictionaries arrived in 9.0.0 with real constraints
The most significant recent feature set is dictionary support, and it comes with conditions that matter. It depends on brotli-decompressor 6.0.0, whose dictionary support is re-exported, so brotli::Decompressor, brotli::DecompressorWriter and brotli::BrotliState all gain attach_dictionary and attach_serialized_dictionary.
attach_dictionary takes a raw LZ77 prefix dictionary and is the equivalent of the C BrotliDecoderAttachDictionary with BROTLI_SHARED_DICTIONARY_RAW. Up to 15 may be attached, and they must be attached before the first read or write. The ordering constraint is a real API trap: attach after the stream has started and the semantics are undefined for you, and the compiler will not stop you.
The second method, attach_serialized_dictionary, accepts the serialized shared dictionary container with the magic bytes 0x91 0x00 from draft-vandevenne-shared-brotli-format, including embedded LZ77 prefix dictionaries, custom word lists, custom transform lists and context based dictionary selection. So a shared dictionary in the interoperable format is supported, not just a raw in memory prefix.
There is also an internal change with user visible consequences. Dictionaries now live in their own buffers rather than being copied into the ring buffer, following the C implementation's compound dictionary scheme, so they stay addressable after the ring buffer wraps. Streams where output plus dictionary exceed the window decode correctly, and dictionaries larger than the window are no longer truncated. Those two sentences describe a class of bugs that older versions had.
The 9.0.0 major bump breaks allocators and FFI callers
Two breaking changes ship in the same version, and both hit people who are not touching compression logic at all.
The first is the allocator generation. The allocator crates move to alloc-no-stdlib 3.x and alloc-stdlib 0.3.x, and because the Allocator and SliceWrapper traits are part of the public API of this crate and of brotli-decompressor, a crate that passes its own allocator to rust-brotli must move to the same generation. With a split, an allocator built against 2.x no longer satisfies the 3.x Allocator bound. The dependency ranges are pinned so the resolver cannot span the major, which turns a silent trait mismatch into a resolution failure, but the compile break still lands on you.
The second is the FFI signature change. BrotliDecoderSetParameter now returns BROTLI_BOOL and takes the parameter selector as an int, matching the prototype in c/brotli/decode.h and the C library. It returns false for an unrecognised selector instead of forming an invalid enum discriminant at the ABI boundary. C callers that ignored the return value are unaffected. Rust callers of CBrotliDecoderSetParameter should pass BrotliDecoderParameter::... as i32. If you bind to the FFI from Rust, that cast is a required change rather than an optional cleanup.
The version history shows the FFI hardening in a broader pattern. The 8.0.4 notes return NULL from BrotliEncoderCreateInstance and BrotliEncoderCreateWorkPool when a caller provided allocator returns NULL rather than writing state through a NULL pointer, wrap mutable Broccoli FFI entry points in a local catch_unwind helper so Rust panics do not unwind across extern C, and reject serialized BroCatli buffers with out of range live state fields before constructing the state. 8.0.2 and 8.0.3 fix a memory leak in the FFI API, CompressMulti worker joins on errors, and a panic across the Broccoli FFI boundary. That history is worth weighing: the FFI is young and has been bleeding.
portable-float trades bytes for reproducibility
There is a non default feature called portable-float that makes encoder output target independent, so the same input compresses to byte identical output on every target. The mechanism is specific: it routes the cost estimators' log2 and powf onto the table driven implementations that no_std builds already use, instead of the platform libm, whose one ULP differences could move a block split boundary.
That is the correct trade-off for a codec used in distributed systems, where two nodes compressing the same input and getting different bytes produces different digests and breaks content addressing. The cost is stated in the notes: the feature is off by default because it changes the emitted bytes and costs about 0.006% of ratio. That is a very small price for determinism, and the fact that it is off by default is mostly a legacy concern for consumers who expect exact reference output.
A second feature change is worth noting for anyone reading the source. The safe feature is now declared in Cargo.toml. The cfg had been referenced from src/ffi since the FFI was added but was never listed, so it could not actually be turned on. With it enabled, the FFI drops the two unsafe impl Send lines and the encoder and multicompress entry points that rely on them, while the decoder FFI is unaffected. A feature flag that did nothing is a good thing to fix, but it also means code compiled with the safe feature on has a different thread safety surface than code compiled with it off.
The simd feature builds on current nightly again after Mask::to_int was renamed to Mask::to_simd, and the seccomp feature builds again because the calloc backed allocator macros are brought into scope in the brotli binary. The 6.0.0 notes also say SIMD is not built as part of the MSRV, since combining nightly with MSRV does not make sense. So SIMD is a nightly only, opt in path.
Version numbers, licences and what to expect from maintenance
The published crate version is 9.0.0 and the licence field in the manifest reads BSD-3-Clause AND MIT, with both LICENSE.BSD-3-Clause and LICENSE.MIT present at the repository root. The two licences are the permissive pair most Rust projects use, and both apply together. Whether that suits a particular embedded product is a question for your own legal review, not for this page.
The version record is confusing and worth reading carefully. The listed GitHub releases are 1.0.110 and 1.0.108, both dated 2019-02-12, and 1.0.106 dated 2019-02-11, while the crate version in Cargo.toml is 9.0.0 and the changelog covers versions 3.x through 9.0.0. The repository is not archived and the last push was on 2026-09-02, so work is continuing on the master branch even though the release tags visible on the repository are old. If you depend on the crate from crates.io you follow the published versions; if you vendor from git you follow master. Do not assume the tags tell you the current state.
The other maintenance signal is the size of the project. This is a large implementation with a C FFI, a no_std mode, SIMD, multicompress and a research directory, and the bug list in the notes touches NULL pointer handling, FFI panics and underflowing arithmetic on truncated metadata headers. The 8.0.4 note about shift_and_check_new_stream_header underflowing on truncated metadata headers is the kind of defect that matters for a decoder exposed to untrusted input, and the fix is present, which is a point in favour, but it also tells you the decoder is the part to test hardest.
Editorial conclusion
Choose rust-brotli when your target has no stable standard library, when you need to hand the encoder a custom allocator, or when you want Brotli in a build that must not link the C library, and stay on the reference C implementation when byte identical output against existing Brotli streams matters. Before you adopt it, check the crate features you intend to enable, because the FFI is off by default, SIMD needs a nightly toolchain and the allocator crates moved to a new major generation in 9.0.0. Verify that your allocator satisfies the alloc-no-stdlib 3.x Allocator bound, and note that the listed GitHub releases are the 1.0.110 and 1.0.108 tags from February 2019 while the crate version in Cargo.toml is 9.0.0, with the last push on 2026-09-02.
Frequently asked questions
What is rust-brotli and what is it used for?
It is a Brotli compressor and decompressor written in Rust, published as the brotli crate. Its interface avoids the Rust standard library, which the crate description says makes it suitable for embedded devices and kernels.
How do I build rust-brotli with SIMD or the C FFI?
The justfile provides separate recipes. The SIMD build uses cargo +nightly build --features simd, and the FFI build uses cargo build --features ffi-api plus a build of the crate in the c directory, where the make file is still used.
Does rust-brotli support custom dictionaries?
Yes, since 9.0.0. attach_dictionary accepts a raw LZ77 prefix dictionary and up to 15 may be attached, but they must be attached before the first read or write, and attach_serialized_dictionary accepts the serialized shared dictionary container from the shared Brotli format draft.
What breaking changes came with rust-brotli 9.0.0?
The allocator crates moved to alloc-no-stdlib 3.x and alloc-stdlib 0.3.x, so a custom allocator built against 2.x no longer satisfies the 3.x Allocator bound. The FFI function BrotliDecoderSetParameter also now returns BROTLI_BOOL and takes the selector as an int.
How do I make rust-brotli produce identical output on every platform?
Enable the non default portable-float feature, which routes the cost estimators' log2 and powf onto table driven implementations instead of the platform libm. The notes state it changes the emitted bytes and costs about 0.006% of ratio.
Official sources
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.
[](https://hysenlabs.com/projects/dropbox-rust-brotli)Was this useful?