Library / SDK
RoaringBitmap/roaring-rs avatar
RoaringBitmap/roaring-rs

roaring-rs: the Roaring bitmap data structure in Rust

A better compressed bitset in Rust

968 stars125 forksRustApache-2.0

At a glance

What is it?
roaring-rs is the Rust port of the Roaring bitmap, the compressed bitset that stores a set of integers as a hybrid of dense arrays, sparse words and run-length containers so that a large set with clumps in it takes less memory than a plain bit vector without giving up the constant time operations. The crate is maintained to a strict standard, its benchmarks run over real datasets, and it follows a stable-Rust-only policy that will decide whether it fits your build.
Who is it for?
Adopt roaring-rs when your Rust code holds large sets of integer identifiers and the memory cost of a bit vector is the problem, because the structure gives up nothing in lookup speed while using far less space, and because the benchmarks in the repository run over real datasets rather than synthetic ones.
Can I use it commercially?
Yes. Apache-2.0 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 received new commits within the last day.
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 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A port of a Java data structure with a paper behind it

roaring-rs is described as a better compressed bitset in Rust, and the README gives its lineage precisely. It is a Rust port of the Roaring bitmap data structure, which was initially defined as a Java library and described in the paper Better bitmap performance with Roaring bitmaps, with the arXiv link given in the reference list. The project site is roaringbitmap.org, the crate is published on crates.io as roaring, and the API documentation is on docs.rs.

The paper link matters for how much confidence to put in the design. A compressed bitset that is a port of an existing library, with a published paper behind the format, is a different proposition from a novel structure, because the format has been implemented and profiled in several languages and the trade-offs are documented.

The idea itself is a hybrid. A plain bit vector stores membership compactly but always costs a full bit per possible value, so a set with a billion possible identifiers and a thousand members still allocates a hundred megabytes. A roaring bitmap splits the value space into chunks, and within each chunk picks a container representation according to the data: a dense array for a small number of set values, a sparse structure for scattered values, and a run-length container for long runs of consecutive values. The result is a structure with constant time membership tests, fast set operations, and memory that tracks the actual content rather than the range of possible values.

For the Rust port the interesting questions are not the data structure, which is settled, but the engineering around it: how the crate is laid out, how it is tested, how it is benchmarked, and what it will do to your build.

The Rust version policy is the first thing to read

The README has a section called Rust version policy, and it is short enough to be quoted in full. This crate only supports the current stable version of Rust, patch releases may use new features at any time.

That is a stricter policy than most crates state, and it has direct consequences for adoption. There is no minimum supported Rust version to build against, in the usual sense, because the crate tracks whatever is current. A patch release, which by most versioning conventions is supposed to be safe to take, may change the language features the crate compiles with, so a patch bump can raise your minimum toolchain.

The badge in the README header confirms it, showing the crate as tracking the latest stable Rust.

For a library this means that the maintainer is free to use the newest stable language features, which keeps the code idiomatic and lets the compiler help, and it means that a project on an older pinned toolchain cannot use the crate at all, or has to pin the crate to an older release and lose the fixes. That is a real trade, and it is the kind of decision a foundation library should make deliberately and publish, which is what the README does.

There is one place the policy is relaxed, and it is worth noticing. The simd feature is in active development, and the README says it has not been tested, and that std::simd is only available in Rust nightly. So the experimental path needs a nightly toolchain while the stable path needs the current stable one, which is a clean split between the supported and the exploratory.

The contribution checks, and what they say about the code

The development section describes the project as using Clippy and rustfmt, and denying warnings in CI builds, with both available through rustup component add clippy rustfmt.

The three checks a contributor is asked to run are these:

bash
cargo fmt -- --check
cargo clippy --all-targets -- -D warnings

plus the test suite, which the README says to ensure is passing with cargo test.

The clippy invocation is the notable one. The -D warnings flag turns every lint into an error, and --all-targets means the lint runs over the tests, the examples and the benchmarks as well as the library. A crate that denies warnings in CI has decided that no lint is allowed to be merely advisory, which is why the code you read has a consistent shape and why a contribution that trips a lint is rejected by the build rather than in review.

Combined with the version policy, this is a picture of a small project with a strict process. The checks are cheap to run locally, and the README asks contributors to run them before submitting, so a pull request that arrives already formatted and lint clean is the normal case rather than the exception.

The repository also carries an .editorconfig and a rustfmt.toml, so the formatting rules are in the tree rather than in a contributor's memory, and the .github directory holds the workflow that enforces the same rules on every push.

Benchmarks over real datasets, on bare metal

The benchmarking section is the most serious part of the README, and it is written by someone who has been burned by noisy benchmarks.

The recommended command is cargo bench, and the benchmarks directory contains a library dedicated to benchmarking the Roaring library using a set of real-world datasets, which live in a separate repository, RoaringBitmap/real-roaring-datasets. The advice is also to run the benchmarks on a bare-metal machine, and then to run them on the base branch and then on the contribution pull request branch, so that the change in performance is what you see rather than the noise of the machine.

Those are three separate pieces of advice and each one is a common failure avoided. Synthetic data, such as uniformly random identifiers, produces a workload that no real workload resembles, and a container implementation would look great on it and badly on production data. Running on a shared or virtualised machine adds variance that can swamp a real difference. And measuring only the new branch gives a number without a baseline, so a change that made things 20 per cent slower still looks like a number.

The benchmarks are built on the Criterion library, and the README links to its user guide, which is the tool that handles the statistical side of comparing two runs.

For an adopter, this is the section to read before trusting any performance claim about the crate, and also the section to read if you want to run the comparison on your own data. The data is public, the harness is in the tree, and the command is one line.

The workspace, the formats and the fuzzing

The Cargo.toml describes a two-member workspace, the roaring crate itself and the benchmarks, with the resolver set to 2.

toml
[workspace]
members = [ "benchmarks", "roaring" ]
resolver = "2"

The dependency list is a good description of what the crate does beyond the bitmap itself. bytemuck and byteorder are for zero-copy reinterpretation of byte buffers into integers and back, which is how a roaring bitmap is deserialised without copying. serde and serde_json are the serialisation support, and postcard appears with its alloc feature, which is a compact binary format that suits a data structure whose whole point is a compact representation. itertools is for the iterator-heavy internals. criterion is the benchmark framework, proptest is for property based testing, and git2, indicatif and zip belong to the benchmark harness, where indicatif draws the progress bar and zip collects the results, which tells you the benchmarks are reproducible runs over a corpus rather than a single quick measurement.

There is a fuzz directory in the repository, which is the part most compressed bitset crates skip. A roaring bitmap has to handle containers in every representation, transitions between them as data changes, and serialised input that may be malformed. Property based tests and fuzzing are the two ways to find the case where the transition logic is wrong, and their presence here is a reasonable signal about the maturity of the implementation.

One more detail in the manifest is worth a sentence. The test profile sets opt-level 2, so the tests and the fuzzing run against optimised code. For a data structure whose failure modes often depend on performance characteristics, and for code that uses debug assertions, that is a sensible choice, though it does mean the test build is slower to compile than a default debug build.

Licence, releases and the judgement to make

The licence is dual, Apache License 2.0 or the MIT licence, at your option, with both texts in the repository as LICENSE-APACHE and LICENSE-MIT. The contribution terms match: unless you explicitly state otherwise, any contribution intentionally submitted for inclusion is dual licensed the same way, with no additional terms. This describes the published terms rather than legal advice.

The release record is regular. Version 0.11.5 was published on 2026-08-12, 0.11.4 on 2026-04-24 and 0.11.3 on 2025-12-15, and the last push was on 2026-10-12. The crate is still below 1.0, which in Rust convention means the API is not yet considered stable, and a project on the 0.11 line should expect breaking changes before 1.0 rather than after it.

The judgement is mostly about whether your use case is the one the structure fits. A roaring bitmap is for a set of integer identifiers that is large in range and irregular in content, which is exactly the shape of a user id set, a document id set, a set of shard numbers or a set of visited keys. If your identifiers are dense and few, a Vec of integers is smaller and simpler, and if your set is small, a HashSet wins on everything except memory. The structure pays for itself when the range is much larger than the population.

The second judgement is the toolchain. A crate that supports only the current stable Rust, and may use new features in a patch release, is a fine dependency for an application that tracks the toolchain and a problem for a library that must build on whatever its users have. Many of the users of a roaring bitmap, though, are themselves infrastructure that moves quickly, and for those the policy is a benefit.

The third is the simd feature, and the answer there is simple. The README says it is in active development and has not been tested, and it needs nightly, so it is not a reason to adopt the crate and it is not something to enable in production.

Editorial conclusion

Adopt roaring-rs when your Rust code holds large sets of integer identifiers and the memory cost of a bit vector is the problem, because the structure gives up nothing in lookup speed while using far less space, and because the benchmarks in the repository run over real datasets rather than synthetic ones. It is the wrong tool for small sets, where a HashSet is simpler, and the wrong tool if you need to build on a pinned older Rust, because the crate supports only the current stable release and may use new features in a patch. Before adopting, check the Rust version your toolchain pins against the version policy, and leave the simd feature off, since the README says it is untested and needs nightly.

Frequently asked questions

What is roaring-rs and what is a Roaring bitmap?

It is the Rust port of the Roaring bitmap data structure, which was first defined as a Java library and described in the paper Better bitmap performance with Roaring bitmaps. The structure stores a set of integers in a hybrid of dense, sparse and run-length containers so that memory tracks the content rather than the range of possible values.

What Rust versions does roaring-rs support?

Only the current stable version of Rust. The README states that the crate supports the current stable release and that patch releases may use new features at any time, so there is no fixed minimum toolchain and a patch bump can raise what you need.

How do I run the roaring-rs benchmarks?

With cargo bench. The benchmarks directory holds a library that runs the benchmarks over real-world datasets from the RoaringBitmap/real-roaring-datasets repository, built on Criterion. The README advises running on a bare-metal machine and comparing the base branch with the pull request branch.

What checks does roaring-rs require before a contribution is accepted?

cargo fmt -- --check for formatting, cargo clippy --all-targets -- -D warnings so that every lint is an error across all targets, and cargo test to make sure the suite passes. The project denies warnings in its CI builds.

Is the simd feature in roaring-rs ready to use?

No. The README says the simd feature is in active development and has not been tested, and that std::simd is only available in Rust nightly, so it needs a nightly toolchain and should not be relied on.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. RoaringBitmap/roaring-rs on GitHub
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/roaringbitmap-roaring-rs.svg)](https://hysenlabs.com/projects/roaringbitmap-roaring-rs)

Was this useful?