Versioning and support
SemVer policy
Section titled “SemVer policy”distillate follows Semantic Versioning.
- Pre-1.0 (
0.x): the public API may change in a minor release. Breaking changes bump the minor (0.1.x->0.2.0); patches stay backward compatible. Pin a version if you depend on it. - Post-1.0: breaking changes bump the major, additive changes the minor, fixes the patch.
The public API is exactly what the committed API reports in etc/ describe (one per entry point, generated by API Extractor). Any change to an exported signature changes those reports, and CI fails until they are regenerated (pnpm api:report), so no breaking change ships unreviewed. Anything not in a report (internal modules, the shared chunk) is not part of the contract and can change at any time.
Serialized-format compatibility
Section titled “Serialized-format compatibility”toBytes / fromBytes use a versioned binary format. A filter serialized by one release must deserialize in later releases of the same major; a format change that breaks this is treated as a breaking change. See serialization.
Compatibility model
Section titled “Compatibility model”From 1.0, format version 5 is frozen until 2.0. A reader accepts exactly one format version, the one its release writes.
This is a deliberate choice. The alternative is a read window, where a release also reads the previous format version and writes only the newest, as Arrow’s MetadataVersion and RocksDB’s format_version do. A window keeps stored data readable across a format change, at the cost of maintaining several reader paths indefinitely. distillate takes the simpler contract and spends its format changes before 1.0 instead.
The consequence for stored data: a format version bump is a major release, and frames written before it cannot be read after it. No structure can be converted from its stored bits, so the only recovery is to rebuild from the source keys. If you persist a filter or sketch across a major upgrade, keep the keys it was built from.
Additive changes, listed below, arrive in minor releases without a format version bump. An older reader rejects a frame that uses one with a typed error rather than misreading it, so a reader must be at least as new as the producer.
Format stability contract
Section titled “Format stability contract”| Change | How it lands | Format version bump |
|---|---|---|
| New structure type | A new type code. Older readers reject it on type (SerializationError). |
No |
| New encoding of an existing type | HyperLogLog: a new encoding value. Bloom, Blocked: a field in the zero-checked params padding. Fuse has no spare byte: a new type code. Older readers reject it cleanly. |
No |
| New header field in reserved space | Sets a reserved bit. Older readers reject it (ReservedBitsError). |
No |
| Hash change | A new flags variant. Older readers reject it (UnknownHashVariantError). |
No |
| Probe scheme or index mapping change | A new flags variant, even when the hash is unchanged. Older readers reject it (UnknownHashVariantError). |
No |
| Payload layout change | A format version bump, which under the frozen model is a major release. | Yes |
Supported runtimes
Section titled “Supported runtimes”distillate targets ES2022, ships zero runtime dependencies, and uses no eval or required WASM, so it runs on every modern JavaScript runtime:
- Node.js 22, 24 (active LTS and current)
- Bun and Deno
- Browsers and Cloudflare / Vercel edge
Every push runs a CI smoke matrix that imports the built package on Node 22/24, Bun, and Deno, so this support is verified, not assumed.
Node.js support policy
Section titled “Node.js support policy”The supported Node range tracks active and current LTS lines. Dropping an end-of-life Node major is not considered a breaking change and may happen in a minor release; it will be called out in the changelog.