Overview
brotli wraps libbrotli — Google's open-source lossless compression algorithm designed for the modern web. All major browsers support it natively via the Accept-Encoding: br / Content-Encoding: br HTTP header pair, making it the preferred format for serving compressed web content.
The library offers both one-shot functions for simple in-memory compression and streaming encoder/decoder handles for processing large inputs in chunks without buffering everything in RAM.
Requires libbrotli-dev. Ubuntu/Debian: sudo apt install libbrotli-dev
Quality Levels
Brotli quality ranges from 0 (fastest, weakest) to 11 (slowest, best ratio). Choose based on your latency vs. size trade-off.
| Quality | Profile | Typical use |
|---|---|---|
| 0–1 | Very fast — comparable to gzip -1 | Real-time API responses, live streams |
| 2–3 | Fast | High-throughput servers with CPU constraints |
| 4–6 | Balanced (default = 6) | General-purpose web serving, most deployments |
| 7–8 | Good ratio | Batch compression jobs, build pipelines |
| 9–11 | Best ratio, slow encode | Pre-compressing static assets (HTML, JS, CSS, fonts) |
Encode once with CompressBest and store the .br files. nginx and Apache serve them directly with zero per-request CPU cost via brotli_static on.
vs. Other Algorithms
| Algorithm | vs. Brotli | Best fit |
|---|---|---|
| gzip | Brotli has 20–26% better ratio; similar or faster decode | Legacy clients, S3/CDN defaults |
| zstd | Similar ratio; zstd encodes faster; brotli better native browser support | Databases, internal services |
| lzma | Brotli decodes much faster; lzma wins on ratio for archives | Installers, archive distribution |
Quick Start
Compress and decompress in one call
uses brotli;
var html := '<!DOCTYPE html><html>...</html>';
{ Quality 6, generic mode }
var compressed := Compress(html, 6, bmGeneric);
WriteLn('Compressed: ' + IntToStr(Length(compressed)) + ' bytes');
var ratio := CompressionRatio(html, compressed);
WriteLn('Ratio: ' + FloatToStr(ratio));
var restored := Decompress(compressed);
WriteLn('Restored: ' + IntToStr(Length(restored)) + ' bytes');
Default and convenience shortcuts
uses brotli;
{ quality=6, bmGeneric — good for most cases }
var data := CompressDefault(payload);
{ quality=11 — slowest, best ratio, ideal for static assets }
var small := CompressBest(payload, bmText);
{ quality=1 — fastest encode }
var fast := CompressFast(payload);
Compress a file to .br
uses brotli;
{ Pre-compress a JS bundle at best quality for nginx brotli_static }
CompressFile('/var/www/app.js', '/var/www/app.js.br', 11, bmGeneric);
{ Decompress later }
DecompressFile('/var/www/app.js.br', '/tmp/app.js');
One-Shot API
Use these functions when the entire input fits comfortably in memory. For large files or network streams, prefer the Streaming API below.
| Function | Description |
|---|---|
| Compress(Data, Quality, Mode) | Compress string with explicit quality (0–11) and mode. Returns compressed bytes as string. |
| CompressDefault(Data) | Compress with quality 6 and bmGeneric mode. |
| CompressBest(Data, Mode) | Compress at quality 11 (best ratio, slower encode). |
| CompressFast(Data) | Compress at quality 1 (fastest encode). |
| Decompress(Data) | Decompress brotli-compressed bytes. Raises on corrupt input. |
| CompressFile(SrcPath, DstPath, Quality, Mode) | Compress a file in place to a .br output path. |
| DecompressFile(SrcPath, DstPath) | Decompress a .br file to the destination path. |
Streaming Encoder API
Feed data in chunks to the encoder — useful when compressing network streams, large log files, or any source where the full input is not known upfront. Call FinishEncoder to flush the final compressed block.
uses brotli;
var enc := NewEncoder(6, bmText);
var i := 0;
while i < Length(chunks) do
begin
EncodeChunk(enc, chunks[i]);
{ FlushEncoder sends partial output without finishing the stream }
var partial := FlushEncoder(enc);
if Length(partial) > 0 then
SendToClient(partial);
i := i + 1;
end;
{ Finish produces the final compressed bytes }
var tail := FinishEncoder(enc);
SendToClient(tail);
FreeEncoder(enc);
| Function | Description |
|---|---|
| NewEncoder(Quality, Mode) | Create a streaming encoder handle. Returns a TBrotliState. |
| FreeEncoder(E) | Release encoder resources. Always call when done. |
| EncodeChunk(E, Data) | Feed a chunk of uncompressed data to the encoder. |
| FlushEncoder(E) | Flush buffered output and return partial compressed bytes (for live streaming). |
| FinishEncoder(E) | Signal end of input and return the final compressed bytes. Must be called once. |
Streaming Decoder API
Decompress data arriving in chunks — for example, reading a compressed HTTP response body as it arrives over the network.
uses brotli;
var dec := NewDecoder();
var chunk := ReadNextChunk();
while chunk <> '' do
begin
var out := DecodeChunk(dec, chunk);
if Length(out) > 0 then
ProcessOutput(out);
chunk := ReadNextChunk();
end;
if DecoderDone(dec) then
WriteLn('Stream fully decoded');
FreeDecoder(dec);
| Function | Description |
|---|---|
| NewDecoder() | Create a streaming decoder handle. |
| FreeDecoder(D) | Release decoder resources. |
| DecodeChunk(D, Data) | Feed a compressed chunk. Returns any decompressed bytes available so far. |
| DecoderDone(D) | Returns True when all input has been consumed and output is complete. |
Utilities API
| Function | Description |
|---|---|
| MaxCompressedSize(InputSize) | Estimate the worst-case compressed output size for InputSize bytes. Use to pre-allocate buffers. |
| IsBrotli(Data) | Heuristic check — returns True if the data looks like a brotli stream. Not a full validation. |
| CompressionRatio(Original, Compressed) | Returns compressed_size / original_size as a Double. Values below 1.0 indicate compression savings. |
| BrotliVersion() | Returns the linked libbrotli version string. |
uses brotli;
WriteLn('libbrotli ' + BrotliVersion());
var maxBuf := MaxCompressedSize(1024 * 1024); { worst case for 1 MB input }
WriteLn('Max output buffer: ' + IntToStr(maxBuf) + ' bytes');
var raw := ReadFile('data.bin');
if IsBrotli(raw) then
raw := Decompress(raw);
Types
TBrotliState
An opaque integer handle returned by NewEncoder and NewDecoder. Pass it to the corresponding chunk/flush/finish/free functions. Do not share a single state between concurrent goroutines or threads without external locking.
type
TBrotliState = Integer; { streaming encoder/decoder handle }
TBrotliMode
Hints to the encoder about the nature of the input data. Using the right mode can improve both compression ratio and speed.
type
TBrotliMode = (
bmGeneric = 0, { default — works for all data }
bmText = 1, { optimized for UTF-8 text }
bmFont = 2 { optimized for WOFF 2.0 fonts }
);
| Mode | Use when |
|---|---|
| bmGeneric | Binary data, mixed content, or unknown input type |
| bmText | HTML, CSS, JavaScript, JSON, plain text (UTF-8) |
| bmFont | WOFF 2.0 web font files — yields meaningful extra savings |
Key Concepts
Web compression workflow
The canonical deployment pattern is to pre-compress all static assets at build time with quality 11 and serve them with a Content-Encoding: br header. Nginx example: brotli_static on;. For dynamic responses (API payloads, SSR HTML) compress on-the-fly at quality 4–6 to keep latency low.
HTTP header negotiation
Clients advertise support with Accept-Encoding: br, gzip. Your server should check for br first and fall back to gzip for older clients. The IsBrotli utility can help detect the encoding of cached or stored blobs.
One-shot functions (Compress, Decompress) buffer the full output in memory. For inputs larger than a few megabytes, use NewEncoder / NewDecoder to keep memory usage bounded.
Package Info
System Requirements
libbrotli-devUbuntu/Debian:
sudo apt install libbrotli-dev
TBrotliMode
bmGeneric — all data typesbmText — UTF-8 textbmFont — WOFF 2.0 fonts
Functions
- Compress
- CompressDefault
- CompressBest
- CompressFast
- Decompress
- CompressFile
- DecompressFile
- NewEncoder / FreeEncoder
- EncodeChunk
- FlushEncoder
- FinishEncoder
- NewDecoder / FreeDecoder
- DecodeChunk
- DecoderDone
- MaxCompressedSize
- IsBrotli
- CompressionRatio
- BrotliVersion