Tiny & performant Zstandard codec for WebAssembly. Decoder + level-1 compressor in a single module. Based on zstd-codec-lib by Tadpole Labs.
This library follows the following criteria:
- Simple API: ZstdCodec class, with synchronous compress and synchronous decompress methods only
- Compression: Level 1 only, no dict support. We benchmarked this as the right compression level for our workload (JSON data)
- Decompression: Up to level 9 (to be future-proof)
- 38kb / 48kb (zipped) for the size/perf-optimized codec
- Based on the zstd reference implementation
- Thoroughly tested
- Zero dependencies
- Given the limitations of wasm memory management and to achieve appropriate code size & performance, memory is allocated to a fixed-size ring buffer, avoiding heap growth entirely. A single WebAssembly instance serves both compression and decompression, time-sharing one 12 MB buffer that is sufficiently sized to handle the maximum memory required by a level-9 frame (4 MB decoder window).
- For use in browsers, the module is asynchronously compiled & cached at page load.
- Only the
fast(lvl 1) strategy is pulled from upstream — heavier strategies (dfast/greedy/lazy/btopt/btultra*) are excluded via the upstreamZSTD_EXCLUDE_*_BLOCK_COMPRESSORmacros, so--gc-sections+ LTO drop them entirely. Higher compression levels are not supported (anylevelother than1throws). - NodeJS supports zstd natively, so it's usually preferable to just use that.
The public API is a single ZstdCodec class — one instance serves both
directions, time-sharing one 12 MB buffer. Obtain one via createCodec()
(which loads and caches the wasm module), then call it synchronously.
import { createCodec } from 'zstd-wasm-codec'; // Default (Node/browser - automatically inferred)
import { createCodec } // For strict CSP policies (no unsafe-eval for WASM)
from 'zstd-wasm-codec/external'; // .wasm fetched from same-origin
import { createCodec } // If you need the extra perf. (+30%) for +10kb in the browser
from 'zstd-wasm-codec/perf' // or perf/external
// non-browser env uses perf. by defaultNote: In development mode, the inlined version is served for /external to avoid bundler issues (e.g., in Vite).
// One codec instance round-trips both ways, reusable across calls.
const codec = await createCodec();
// Compression — level 1 only (see caveats below).
const compressed: Uint8Array = codec.compressSync(input);
// Decompression (buffer already in memory).
const decoded: Uint8Array = codec.decompressSync(compressed);- Level 1 only — only the
faststrategy is included to keep the binary small. Anylevelother than1throws. If you need maximum ratio you'll need a different library. - The codec uses a fixed 12 MB linear memory. Allocation happens up front; the wasm doesn't grow at runtime.
- The compressor emits level-1 frames (512 KB window); the decoder accepts foreign frames up to level 9 (4 MB window). Frames declaring a larger window — e.g. level-19 output from the
zstdCLI — are refused withframeParameter_windowTooLarge. - Output frames are spec-compliant — round-tripping through the upstream
zstdCLI is verified by CI.
- The default export is pre-minified and mangled. All builds tested against the full suite.
- Legacy ZSTD format is not supported, and the presence of magic bytes is expected.
- Dictionaries are not supported (in either direction). Frames that reference a dictionary ID fail with
ZSTD_error_dictionary_wrong. - Consult the reference to interpret error codes, should any occur.
- Do not use the wasm module standalone (without js).
The toolchain is defined via Nix in shell.nix. It is recommended to use direnv to load the correct tools during development, but nix-shell can also be used.
### Development Workflow
```bash
# Full build (WASM + TypeScript)
yarn build
# Clean build
yarn clean
yarn build
# Run tests
yarn test # All runtimes (Node + browsers + Bun)
yarn test:node # Node.js only — includes the codec suite
yarn test:codec # Codec round-trip + cross-decode tests only
yarn test:browsers # Browser tests only
yarn test:bun # Bun only
# Run benchmarks
yarn bench:full
This package is dual-licensed under Apache-2.0 OR MIT
The underlying zstd implementation is licensed under BSD-3-Clause.