brotli_fast
A fast, pure Dart Brotli encoder and decoder with no native dependencies and no package dependencies. It runs everywhere Dart runs (VM, AOT, Flutter, and the web through dart2js and dart2wasm) and produces the same bytes on every platform.
import 'package:brotli_fast/brotli_fast.dart';
final packed = brotliEncode(bytes); // quality 5
final smallest = brotliEncode(bytes, quality: 11);
final restored = brotliDecode(packed);
Features
- All of Brotli: qualities 0–11 and window sizes 10–24 bits on the encoder, and the full RFC 7932 format on the decoder, including the static dictionary and every transform.
- Fast: a dedicated fast tier for qualities 0–5 and a tuned high-ratio encoder for 6–11; a decoder with a fused hot loop and a 64-bit bit reader on the VM. See Performance.
- One-shot,
dart:convertand streams:brotliEncode/brotliDecode, thebrotlicodec, and stream transformers that emit output as input arrives. - Dictionaries: raw (compound) dictionaries for both directions, which help small, similar payloads, and serialized shared dictionaries on decode.
- Large-window format: windows up to 1 GiB (non-standard, opt-in on decode).
- Safe decoding: malformed or truncated input throws a typed
BrotliException, and a size limit guards against decompression bombs. - Checked against the reference: CI decodes our streams with Google's
brotliCLI, and theirs with ours, at every quality.
Usage
One-shot
import 'package:brotli_fast/brotli_fast.dart';
final packed = brotliEncode(data, quality: 9);
final restored = brotliDecode(packed);
quality trades speed for size: 0–5 favor speed (5, the default, is a
good balance), 6–11 favor ratio and get progressively slower.
windowBits (default 22, a 4 MiB window) can be lowered to save memory on
the decoding side.
Strings
import 'dart:convert';
final text = utf8.fuse(brotli);
final packed = text.encode('héllo, wörld');
final restored = text.decode(packed);
Streams
brotli.encoder and brotli.decoder are stream transformers:
import 'dart:io';
await File('data.json')
.openRead()
.transform(brotli.encoder)
.pipe(File('data.json.br').openWrite());
await File('data.json.br')
.openRead()
.transform(brotli.decoder)
.pipe(File('data.json').openWrite());
Use BrotliCodec(quality: 9) or BrotliEncoder(quality: 9) for other
settings. The streaming encoder emits a compressed block for every 128 KiB of
input. It keeps the input it has seen in memory, so it bounds latency, not
memory.
Dictionaries
When many small payloads share structure (JSON with a common schema, HTML templates), a dictionary known to both sides shrinks them considerably:
final dictionary = BrotliDictionary(utf8.encode(sampleRecords));
final packed = brotliEncode(record, quality: 9, dictionary: dictionary);
final restored = brotliDecode(packed, dictionary: dictionary);
Reuse one BrotliDictionary instance: its match index is built on the first
encode. The decoder must be given the same bytes. Brotli streams carry no
dictionary checksum, so a different dictionary decodes to different data.
Decoding untrusted input
try {
final restored = brotliDecode(input, maxOutputSize: 10 << 20); // 10 MiB
} on BrotliException catch (e) {
print('rejected: ${e.code.name}'); // e.g. truncatedInput, outputLimitExceeded
}
brotliDecode limits output to 1 GiB by default. BrotliException is a
FormatException.
Performance
| quality | text encode | text decode | binary encode | binary decode |
|---|---|---|---|---|
| 0 | 1518 | 2915 | 512 | 1145 |
| 1 | 1185 | 3349 | 520 | 1146 |
| 5 (default) | 855 | 3328 | 357 | 1306 |
| 9 | 92 | 2815 | 26 | 1329 |
Throughput in MB/s on the deterministic 1 MiB text and binary corpus of
benchmark/, measured AOT on an Apple M5 (median of 5 runs).
Numbers are machine-specific; run dart run benchmark/perf_history.dart to
measure on your own hardware. benchmark/HISTORY.md
tracks them over time.
Compatibility
- Streams: standard RFC 7932, readable by any Brotli decoder (browsers,
the
brotliCLI, HTTP servers and proxies). Large-window streams (windowBitsabove 24) need a decoder that opts in. - Platforms: Dart SDK 3.13+; VM, AOT, Flutter, dart2js and dart2wasm. Web builds produce byte-identical output to the VM.
API Documentation
See the API documentation.
Source
The official source code is hosted @ GitHub.
Features and bugs
Please file feature requests and bugs at the issue tracker.
Origin
brotli_fast is inspired by
brotli_neo (repository
dart_brotli, MIT license): a full rewrite as a pure Dart Brotli package,
with:
- One optimized implementation: up to 1.7× faster encoding at the default quality and 2.2× at quality 9, with output byte-identical to brotli_neo's.
- A new, simpler API:
brotliEncode/brotliDecode, thebrotlidart:convertcodec with stream support, andBrotliDictionary. - Correctness fixes: valid streams that failed or decoded wrongly now
decode correctly, and every quality is cross-checked against Google's
reference
brotlitool in CI. - No dependencies.
License
Apache License 2.0. Includes the RFC 7932 static dictionary and tables from google/brotli (MIT); see NOTICE.
Libraries
- brotli_fast
- Fast, pure Dart Brotli (RFC 7932) encoder and decoder.