Compression
One-Shot Compression
The simplest way to compress data - default level 3:
const zstd = @import("zstd");
const compressed = try zstd.compress(allocator, data);
defer allocator.free(compressed);compress signature from:
pub fn compress(allocator: std.mem.Allocator, src: []const u8) anyerror![]u8Compressed Block Encoding
Compression follows the Zstandard 1.6.0 specification: block headers, literal sections, and FSE-encoded sequence sections all conform exactly.
compress emits spec-compliant Compressed_Blocks natively:
- LZ77 match finding over a hash chain (4-byte hash, configurable depth)
- Raw/RLE literal sections per the literals header spec (1/2/3-byte sizes)
- Sequence section with predefined FSE tables for literal-length, offset and match-length codes, plus extra-bit tails - encoded through native Zig FSE table construction and symbol encoding
- Automatic fallback to
Raw_Blockwhen compression does not help
Compression Levels (i32)
Levels are plain i32, range -131072 to 22 (see constants.c_level_min/max). Use zstd.compressWithLevel for numeric control:
// Numeric levels 1-22 (and negative levels for fast modes)
const fast = try zstd.compressWithLevel(allocator, data, 1);
const balanced = try zstd.compressWithLevel(allocator, data, 3);
const best = try zstd.compressWithLevel(allocator, data, 19);
const custom = try zstd.compressWithLevel(allocator, data, 12);
// Helpers
const min = zstd.minCLevel(); // -131072
const max = zstd.maxCLevel(); // 22
const def = zstd.defaultCLevel(); // 3compressWithLevel signature:
pub fn compressWithLevel(allocator: std.mem.Allocator, src: []const u8, level: i32) anyerror![]u8Note: There is no
CLevelenum. Earlier docs referencedCLevel.fastest/default/best; use plaini32instead.
CompressionOptions
For fine-grained control use zstd.compressWithOptions:
pub const CompressionOptions = struct {
level: i32 = 3,
windowLog: u8 = 0,
hashLog: u8 = 0,
chainLog: u8 = 0,
searchLog: u8 = 0,
minMatch: u8 = 0,
targetLength: u32 = 0,
strategy: Strategy = .fast,
checksum: bool = false,
dictId: u32 = 0,
contentSize: ?u64 = null,
};const opts = zstd.CompressionOptions{
.level = 9,
.checksum = true,
.windowLog = 20,
.strategy = .lazy2,
};
const compressed = try zstd.compressWithOptions(allocator, data, opts);
defer allocator.free(compressed);
// Or derive tuned options for a level + source size
var tuned = zstd.getCompressionParameters(12, data.len, 0);
tuned.checksum = true;
const c2 = try zstd.compressWithOptions(allocator, data, tuned);
defer allocator.free(c2);| Field | Type | Default | Description |
|---|---|---|---|
level | i32 | 3 | Compression level (minCLevel..maxCLevel) |
windowLog | u8 | 0 | Window log override (0 = auto) |
hashLog | u8 | 0 | Hash log override |
chainLog | u8 | 0 | Chain log override |
searchLog | u8 | 0 | Search log override |
minMatch | u8 | 0 | Minimum match length |
targetLength | u32 | 0 | Target length |
strategy | Strategy | .fast | fast, dfast, greedy, lazy, lazy2, btlazy2, btopt, btultra, btultra2 |
checksum | bool | false | Enable XXH64 checksum |
dictId | u32 | 0 | Dictionary ID for frame header |
contentSize | ?u64 | null | Pledged source size (null = auto) |
Reusable CompressionContext
For compressing multiple buffers with the same settings:
var cctx = zstd.CompressionContext.init(allocator);
defer cctx.deinit();
// Or with level
var cctx2 = zstd.CompressionContext.initWithLevel(allocator, 9);
defer cctx2.deinit();
// Compress with allocator
const c1 = try cctx.compressAlloc(data1);
defer allocator.free(c1);
const c2 = try cctx.compressAlloc(data2);
defer allocator.free(c2);
// Compress into preallocated buffer
var buf: [4096]u8 = undefined;
const written = try cctx.compress(&buf, data);CompressionContext Methods
| Method | Signature | Description |
|---|---|---|
init | init(allocator: Allocator) CompressionContext | Create with default level 3 |
initWithLevel | initWithLevel(allocator: Allocator, level: i32) CompressionContext | Create with numeric level |
deinit | deinit(self: *CompressionContext) void | Release resources |
setLevel | setLevel(self: *CompressionContext, level: i32) void | Change compression level |
setChecksum | setChecksum(self: *CompressionContext, flag: bool) void | Enable/disable checksum |
setWindowLog | setWindowLog(self: *CompressionContext, log: u8) void | Set window log |
setPledgedSrcSize | setPledgedSrcSize(self: *CompressionContext, size: ?u64) void | Set content size for header |
compress | compress(self: *CompressionContext, dst: []u8, src: []const u8) !usize | Compress into preallocated buffer |
compressAlloc | compressAlloc(self: *CompressionContext, src: []const u8) anyerror![]u8 | Compress with allocator |
reset | reset(self: *CompressionContext) void | Reset streaming state |
cctx.setLevel(5);
cctx.setChecksum(true);
cctx.setWindowLog(22);
cctx.setPledgedSrcSize(@as(?u64, data.len));
cctx.reset(); // reuse for new jobcompressBound / compressInto
Pre-allocate output buffers. compressBound is a worst-case guarantee, not an estimate: a buffer of exactly that size holds the frame for any input of that length, at any level. It fails only for a size the format cannot represent (at or above MAX_INPUT_SIZE), rather than wrapping.
const bound = try zstd.compressBound(src.len);
var buf = try allocator.alloc(u8, bound);
defer allocator.free(buf);
const written = try zstd.compressInto(allocator, buf, src, 3);compressInto returns error.DstSizeTooSmall when dst is below the bound, so a short buffer is reported rather than yielding a truncated frame.
Checksum
Enable frame checksum for data integrity verification:
const opts = zstd.CompressionOptions{ .checksum = true };
const compressed = try zstd.compressWithOptions(allocator, data, opts);
// The decompressor will verify the checksum automatically; use DecompressionOptions.forceIgnoreChecksum to skip