Flavors · one engine, pluggable codecs
Pick the codec that matches your ids.
@cloudbitmaps/core is codec-agnostic. The cache over immutable generations, the load-and-publish write path, chunk-skipping intersection, generation GC, erasure-by-rewrite, encryption, retention and the four storage drivers live there and do not change. A flavor decides one thing — how a chunk of ids is represented on the wire and at rest.
Choose one
One of these ships. The other two are on this page so the shape of the plan is visible — there is no page for a package you cannot install, and a row becomes a link the day it publishes.
| Flavor | Status | Take it when | Cost of choosing it |
|---|---|---|---|
| @cloudbitmaps/roaring Adaptive containers — array, bitset, run | Shipped · v0.10.0 | Ids are sparse or clustered and adaptive containers do real compression work. The default: if you are moving off Redis sets, start here. | A native dependency and its platform matrix. |
| @cloudbitmaps/bitset One bit per id — no containers, no branches | Not planned | Nothing, and that is a measured result rather than an opinion. Above about 6% density a Roaring chunk is an uncompressed bitset, so there is no size to win: on the shape built to favour a plain bitset it comes out 2% ahead, and Roaring wins the other three by 543×, 63× and 1.88×. | It would be a plausible wrong turn — picked for dense ids, where Roaring has already become the same bitset. |
| @cloudbitmaps/soaring A separate algorithm, unproven | Research | Under research, with nothing to install. It ships only if the algorithm proves out against roaring on real workloads — and if it does not, this row goes away. | — |
Adding a flavor is one row here and one figure on its own page. Nothing else on the site changes, because nothing else depends on the codec.
Where the choice does not matter
Every flavor is a codec plugged into the same store. Swapping one is an import change and a re-load of your segments — the drivers, the forward-only pointer protocol, the cache and the container format around the payload all stay put.
Cost
$82.40 per million cold intersects of two segments sharing 100 of 1,999 chunks, from requests measured on S3, and $11.20 per million loads written and published, pointer included — store.load() is expected at about twice that — against $346/mo standing for a Redis-HA node. Billed by the request either way — a codec changes bytes, not the pricing model.
The moat
100 of 2,000 chunks fetched when intersecting two 2,000,000-id segments — the shared keys only. Key alignment happens above the codec, so it survives every flavor. Step through it.
When to walk away
No flavor fixes this. Sub-millisecond p99 on a working set that fits a bounded cache is a different machine; a membership check that misses the cache costs one ranged GET against object storage, where a RAM store costs a memory read. Use Redis.
The API, whichever you pick
has · count · iterate, and the full set algebra — intersect, union, andNot — plus *Into variants that publish the result as a new generation of a destination segment instead of returning it. Data arrives the one way whichever you pick — store.load, one immutable object then a forward-only pointer move. A flavor is a CodecInterface implementation underneath four drivers and two tiers, and changes none of these signatures.
Start with roaring.
It is the one that ships, and it is the right default unless you already know your ids are dense. The memory drivers need no configuration, so the quickstart runs before you decide anything about storage.
npm i @cloudbitmaps/roaring @cloudbitmaps/s3
# the memory and local drivers need nothing else
# for a real backend, add its package:
# @cloudbitmaps/s3 · @cloudbitmaps/gcs · @cloudbitmaps/azure-blob