
Product
Socket for Jira Is Now Available
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.
node-liblzma
Advanced tools
Native Node.js bindings for liblzma — XZ/LZMA2 compression with browser support via WebAssembly.
XZ is a container for compressed archives. It offers one of the best compression ratios available, with a good balance between compression time and decompression speed/memory.
Only LZMA2 is supported for compression output. But the library can open and read any LZMA1 or LZMA2 compressed file.
npm install node-liblzma
import { xzAsync, unxzAsync, createXz, createUnxz } from 'node-liblzma';
// Simple: Compress a buffer
const compressed = await xzAsync(Buffer.from('Hello, World!'));
const decompressed = await unxzAsync(compressed);
// Streaming: Compress a file
import { createReadStream, createWriteStream } from 'fs';
createReadStream('input.txt')
.pipe(createXz())
.pipe(createWriteStream('output.xz'));
// With progress monitoring
const compressor = createXz();
compressor.on('progress', ({ bytesRead, bytesWritten }) => {
console.log(`${bytesRead} bytes in → ${bytesWritten} bytes out`);
});
import { xzAsync, unxzAsync } from 'node-liblzma';
xzAsync(Buffer.from('Hello, World!'))
.then(compressed => {
console.log('Compressed size:', compressed.length);
return unxzAsync(compressed);
})
.then(decompressed => {
console.log('Decompressed:', decompressed.toString());
})
.catch(err => {
console.error('Compression failed:', err);
});
import { xz, unxz } from 'node-liblzma';
xz(Buffer.from('Hello, World!'), (err, compressed) => {
if (err) throw err;
unxz(compressed, (err, decompressed) => {
if (err) throw err;
console.log('Decompressed:', decompressed.toString());
});
});
📖 Full API documentation: oorabona.github.io/node-liblzma
types declarations in workspace tsconfigssrc/types.ts as single source of truth; index.d.ts re-exports from compiled output instead of duplicating definitionsPresetType broadened — Was 6 | 9, now number (accepts all valid preset values 0-9 + extreme flag)Live Demo — Try XZ compression in your browser.
xzAsync, unxzAsync, createXz, createUnxz)import from 'node-liblzma/inline'-z, -d, -l, -k, -f, -c, -o, -v, -q-e)tar)-B).tar.xz archives — Node.js streaming + browser WASMxzAsync() and unxzAsync()In previous versions, N-API replaced nan as the stable ABI for native modules.
Tested on: Linux x64, macOS (x64/arm64), Raspberry Pi 2/3/4, Windows.
Prebuilt binaries are bundled for: Windows x64, Linux x64, macOS x64/arm64.
| Flag | Description | Default | Values |
|---|---|---|---|
USE_GLOBAL | Use system liblzma library | yes (no on Windows) | yes, no |
RUNTIME_LINK | Static or shared linking | shared | static, shared |
ENABLE_THREAD_SUPPORT | Enable thread support | yes | yes, no |
If no prebuilt binary matches your platform, node-gyp will compile from source automatically.
Live Demo — Try XZ compression in your browser right now.
node-liblzma v3.0.0+ supports XZ compression in the browser via WebAssembly. The same API works in both Node.js and browsers — bundlers (Vite, Webpack, esbuild) automatically resolve the WASM-backed implementation.
// Bundlers auto-resolve to WASM in browser, native in Node.js
import { xzAsync, unxzAsync, isXZ } from 'node-liblzma';
// Compress
const compressed = await xzAsync('Hello, browser!');
// Decompress
const original = await unxzAsync(compressed);
// Check if data is XZ-compressed
if (isXZ(someBuffer)) {
const data = await unxzAsync(someBuffer);
}
import { createXz, createUnxz } from 'node-liblzma';
// Compress a fetch response
const response = await fetch('/large-file.bin');
const compressed = response.body.pipeThrough(createXz({ preset: 6 }));
// Decompress
const decompressed = compressedStream.pipeThrough(createUnxz());
| Import | When to use |
|---|---|
node-liblzma | Standard — bundler resolves to WASM (browser) or native (Node.js) |
node-liblzma/wasm | Explicit WASM usage in Node.js (no native addon needed) |
node-liblzma/inline | Zero-config — WASM embedded as base64 (no external file to serve) |
// Explicit WASM (works in Node.js too, no native build required)
import { xzAsync } from 'node-liblzma/wasm';
// Inline mode (larger bundle, but no WASM file to configure)
import { ensureInlineInit, xzAsync } from 'node-liblzma/inline';
await ensureInlineInit(); // Decodes embedded base64 WASM
const compressed = await xzAsync(data);
xzSync() / unxzSync() throw LZMAError in browsersxzFile() / unxzFile() are not availablecreateXz() / createUnxz() (Web TransformStream) instead of Xz / Unxz classes| Component | Raw | Gzipped |
|---|---|---|
| liblzma.wasm | ~107KB | ~52KB |
| Glue code (liblzma.js) | ~6KB | ~2KB |
| Total | ~113KB | ~54KB |
For detailed browser setup instructions, see docs/BROWSER.md.
This package includes nxz, a portable xz-like CLI tool that works on any platform with Node.js.
# Global installation (recommended for CLI usage)
npm install -g node-liblzma
# Then use directly
nxz --help
# Compress a file (creates file.txt.xz, deletes original)
nxz file.txt
# Decompress (auto-detected from .xz extension)
nxz file.txt.xz
# Keep original file (-k)
nxz -k file.txt
# Maximum compression (-9) with extreme mode (-e)
nxz -9e large-file.bin
# Compress to stdout (-c) for piping
nxz -c file.txt > file.txt.xz
# List archive info (-l / -lv for verbose)
nxz -l file.txt.xz
# Benchmark native vs WASM performance (-B)
nxz -B file.txt
nxz can create, list, and extract .tar.xz archives — auto-detected from file extension:
# Create a tar.xz archive from files/directories
nxz -T src/ lib/ README.md -o project.tar.xz
# List archive contents
nxz -Tl project.tar.xz
# Extract archive to a directory
nxz -Td project.tar.xz -o output/
# Extract with path stripping (like tar --strip-components)
nxz -Td project.tar.xz --strip=1 -o output/
Archives created by nxz are fully compatible with system tar -xJf.
| Option | Long | Description |
|---|---|---|
-z | --compress | Force compression mode |
-d | --decompress | Force decompression mode |
-l | --list | List archive information |
-T | --tar | Treat file as tar.xz archive (auto-detected for .tar.xz/.txz) |
-B | --benchmark | Benchmark native vs WASM performance |
-k | --keep | Keep original file (don't delete) |
-f | --force | Overwrite existing output file |
-c | --stdout | Write to stdout, keep original file |
-o | --output=FILE | Write output to specified file (or directory for tar extract) |
-v | --verbose | Show progress for large files |
-q | --quiet | Suppress warning messages |
-0..-9 | Compression level (default: 6) | |
-e | --extreme | Extreme compression (slower) |
--strip=N | Strip N leading path components on tar extract | |
-h | --help | Show help |
-V | --version | Show version |
# Standalone nxz-cli package (recommended — smaller, faster install)
npx nxz-cli --help
pnpm dlx nxz-cli --help
# Or via the full node-liblzma package
npx --package node-liblzma nxz --help
pnpm dlx --package node-liblzma nxz --help
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Error (file not found, format error, etc.) |
| 130 | Interrupted (SIGINT/Ctrl+C) |
node-liblzma powers a family of focused packages:
| Package | Description | Install |
|---|---|---|
node-liblzma | Core XZ library — Node.js native + browser WASM | npm i node-liblzma |
tar-xz | Create/extract .tar.xz archives — Node.js + browser | npm i tar-xz |
nxz-cli | Standalone CLI — npx nxz-cli file.txt | npx nxz-cli |
Live Demo — Create and extract tar.xz archives in your browser.
A library for working with .tar.xz archives, with dual Node.js (streaming) and browser (buffer-based) APIs. This fills the gap left by node-tar which does not support .tar.xz.
// Node.js — streaming API
import { create, extract, list } from 'tar-xz';
await create({ file: 'archive.tar.xz', cwd: './src', files: ['index.ts', 'utils.ts'] });
const entries = await list({ file: 'archive.tar.xz' });
await extract({ file: 'archive.tar.xz', cwd: './output' });
// Browser — buffer-based API
import { createTarXz, extractTarXz, listTarXz } from 'tar-xz';
const archive = await createTarXz({ files: [{ name: 'hello.txt', content: data }] });
const files = await extractTarXz(archive);
const entries = await listTarXz(archive);
A lightweight wrapper package for running nxz without installing the full node-liblzma:
# No install needed
npx nxz-cli file.txt # compress
npx nxz-cli -d file.txt.xz # decompress
npx nxz-cli -T src/ -o app.tar.xz # create tar.xz archive
# Or install globally
npm install -g nxz-cli
The API mirrors Node.js Zlib for easy adoption:
// CommonJS
var lzma = require('node-liblzma');
// TypeScript / ES6 modules
import * as lzma from 'node-liblzma';
| Zlib | node-liblzma | Arguments |
|---|---|---|
createGzip | createXz | ([options]) |
createGunzip | createUnxz | ([options]) |
gzip | xz | (buf, [options], callback) |
gunzip | unxz | (buf, [options], callback) |
gzipSync | xzSync | (buf, [options]) |
gunzipSync | unxzSync | (buf, [options]) |
| - | xzAsync | (buf, [options]) → Promise<Buffer> |
| - | unxzAsync | (buf, [options]) → Promise<Buffer> |
| - | xzFile | (input, output, [options]) → Promise<void> |
| - | unxzFile | (input, output, [options]) → Promise<void> |
| Attribute | Type | Description | Values |
|---|---|---|---|
check | number | Integrity check | check.NONE, check.CRC32, check.CRC64, check.SHA256 |
preset | number | Compression level (0-9) | preset.DEFAULT (6), preset.EXTREME |
mode | number | Compression mode | mode.FAST, mode.NORMAL |
threads | number | Thread count | 0 = auto (all cores), 1 = single-threaded, N = N threads |
filters | array | Filter chain | filter.LZMA2, filter.X86, filter.ARM, etc. |
chunkSize | number | Processing chunk size | Default: 64KB |
For further information, see the XZ SDK documentation.
Multi-threaded compression is available when built with ENABLE_THREAD_SUPPORT=yes (default).
| Value | Behavior |
|---|---|
0 | Auto-detect: use all available CPU cores |
1 | Single-threaded (default) |
N | Use exactly N threads |
import { createXz, hasThreads } from 'node-liblzma';
if (hasThreads()) {
const compressor = createXz({ threads: 0 }); // auto-detect
}
Note: Threads only apply to compression, not decompression.
Track compression and decompression progress in real-time:
import { createXz, createUnxz } from 'node-liblzma';
const compressor = createXz({ preset: 6 });
compressor.on('progress', ({ bytesRead, bytesWritten }) => {
const ratio = bytesWritten / bytesRead;
console.log(`Progress: ${bytesRead} in, ${bytesWritten} out (ratio: ${ratio.toFixed(2)})`);
});
inputStream.pipe(compressor).pipe(outputStream);
Progress events fire after each chunk is processed. Works with streams, not buffer APIs.
For production environments with high concurrency needs:
import { LZMAPool } from 'node-liblzma';
const pool = new LZMAPool(10); // Max 10 concurrent operations
pool.on('metrics', (metrics) => {
console.log(`Active: ${metrics.active}, Queued: ${metrics.queued}`);
});
const compressed = await pool.compress(buffer);
const decompressed = await pool.decompress(compressed);
import { xzFile, unxzFile } from 'node-liblzma';
await xzFile('input.txt', 'output.txt.xz');
await unxzFile('output.txt.xz', 'restored.txt');
// With options
await xzFile('large-file.bin', 'compressed.xz', { preset: 9, threads: 4 });
Handles files > 512MB automatically via streams with lower memory footprint.
Typed error classes for precise error handling:
import {
xzAsync, LZMAError, LZMAMemoryError, LZMADataError, LZMAFormatError
} from 'node-liblzma';
try {
const compressed = await xzAsync(buffer);
} catch (error) {
if (error instanceof LZMAMemoryError) {
console.error('Out of memory:', error.message);
} else if (error instanceof LZMADataError) {
console.error('Corrupt data:', error.message);
} else if (error instanceof LZMAFormatError) {
console.error('Invalid format:', error.message);
}
}
Available error classes: LZMAError (base), LZMAMemoryError, LZMAMemoryLimitError, LZMAFormatError, LZMAOptionsError, LZMADataError, LZMABufferError, LZMAProgrammingError.
const stream = createXz({
preset: lzma.preset.DEFAULT,
chunkSize: 256 * 1024 // 256KB chunks (default: 64KB)
});
| File Size | Recommended chunkSize |
|---|---|
| < 1MB | 64KB (default) |
| 1-10MB | 128-256KB |
| > 10MB | 512KB-1MB |
Maximum buffer size: 512MB per operation (security limit). For larger files, use streaming APIs.
The low-level native callback follows an errno-style contract matching liblzma behavior:
(errno: number, availInAfter: number, availOutAfter: number)errno is LZMA_OK or LZMA_STREAM_ENDerrno valueHigh-level APIs remain ergonomic — Promise functions resolve to Buffer or reject with Error, stream users listen to error events.
All three backends use the same liblzma library and produce identical compression ratios:
System xz > nxz native (C++ addon) > nxz WASM (Emscripten)
fastest ~1-2x slower ~2-5x slower (decompress)
~1x (compress, large files)
| Backend | Compress | Decompress | Size | Environment |
|---|---|---|---|---|
System xz 5.8 | 81 ms | 4 ms | 76.7 KB | C binary |
| nxz native | 90 ms | 3.4 ms | 76.7 KB | Node.js + C++ addon |
| nxz WASM | 86 ms | 7.9 ms | 76.7 KB | Node.js + Emscripten |
| Data | Compress | Decompress | Notes |
|---|---|---|---|
| 1 KB text | WASM 2.8x slower | WASM 4.9x slower | Startup overhead dominates |
| 135 KB binary | ~1:1 | WASM 2x slower | Compression near-parity |
| 246 KB source | ~1:1 | WASM 2.3x slower | Realistic workload |
| 1 MB random | ~1:1 | WASM 1.6x slower | Gap narrows with size |
# Compare nxz (native) vs system xz across file sizes
./scripts/benchmark.sh
./scripts/benchmark.sh -s 1,50,200 -p 6,9 # custom sizes/presets
./scripts/benchmark.sh -o csv > results.csv # export as CSV/JSON
# Compare native addon vs WASM backend
nxz --benchmark file.txt
nxz -B -3 large-file.bin # with preset 3
| Scenario | Recommended |
|---|---|
| Browser | WASM (only option) |
| Node.js, performance-critical | Native addon |
| Node.js, no C++ toolchain available | WASM (node-liblzma/wasm) |
| Cross-platform scripts | nxz CLI |
| Batch processing many files | System xz |
| CI/CD with Node.js already installed | nxz CLI |
npm install node-liblzma
# or
pnpm add node-liblzma
If prebuilt binaries don't match your platform, install system development libraries:
# Debian/Ubuntu
sudo apt-get install liblzma-dev
# macOS
brew install xz
# Windows (automatic download and build)
npm install node-liblzma --build-from-source
# Force rebuild with default options
npm install node-liblzma --build-from-source
# Disable thread support
ENABLE_THREAD_SUPPORT=no npm install node-liblzma --build-from-source
If you compiled XZ outside of node-liblzma:
export CPATH=$HOME/path/to/headers
export LIBRARY_PATH=$HOME/path/to/lib
export LD_LIBRARY_PATH=$HOME/path/to/lib:$LD_LIBRARY_PATH
npm install
pnpm test # Run all tests
pnpm test:watch # Watch mode
pnpm test:coverage # Coverage report
pnpm type-check # TypeScript type checking
Tests use Vitest with 100% code coverage across statements, branches, functions, and lines.
Node.js >= 22 required — Node 20 reached end-of-life in April 2026. If you must support Node 20, stay on v4.x.
TypeScript 6 — If your project uses TypeScript, you'll need TS 6.x to compile with this version's type definitions.
The JavaScript/TypeScript API is identical to v4.x — xzAsync, unxzAsync, createXz, createUnxz, and all other functions work the same way. This is a toolchain-only breaking change.
// v3.x (deprecated, now removed)
import lzma from 'node-liblzma';
// v4.x (use named imports)
import * as lzma from 'node-liblzma';
// or import individual functions
import { xzAsync, unxzAsync, createXz } from 'node-liblzma';
FlagType removed — Use number directly for stream flags// v3.x
const flags: FlagType = ...;
// v4.x
const flags: number = ...;
LZMAOptions, ProgressInfo, XZFileIndex, etc.) are now re-exported from src/types.ts — import paths unchangedPresetType accepts all preset values (was restricted to 6 | 9)import instead of require)// Promise-based APIs (recommended)
const compressed = await xzAsync(buffer);
// Typed error classes
import { LZMAMemoryError, LZMADataError } from 'node-liblzma';
// Concurrency control
const pool = new LZMAPool(10);
const results = await Promise.all(files.map(f => pool.compress(f)));
// File helpers
await xzFile('input.txt', 'output.txt.xz');
We welcome contributions! See the full contributing guidelines below.
git clone https://github.com/oorabona/node-liblzma.git
cd node-liblzma
pnpm install
pnpm build
pnpm test
pnpm test # Run tests
pnpm test:watch # Watch mode
pnpm test:coverage # Coverage report
pnpm check # Lint + format check (Biome)
pnpm check:write # Auto-fix lint/format
pnpm type-check # TypeScript types
We follow Conventional Commits:
feat: add LZMAPool for concurrency control
fix: resolve memory leak in FunctionReference
docs: add migration guide for v2.0
feat/, fix/, refactor/, docs/)pnpm check:write && pnpm type-check && pnpm testFor maintainers: see docs/RELEASING.md for the complete release process (version bump, changelog, npm publish, cross-repo notifications).
"Cannot find liblzma library" — Install system dev package:
sudo apt-get install liblzma-dev # Debian/Ubuntu
brew install xz # macOS
"node-gyp rebuild failed" — Install build tools:
sudo apt-get install build-essential python3 # Linux
xcode-select --install # macOS
npm install --global windows-build-tools # Windows
"Prebuilt binary not found" — Build from source:
npm install node-liblzma --build-from-source
LZMAMemoryError — Input too large for buffer API. Use streaming:
createReadStream('large.bin').pipe(createXz()).pipe(createWriteStream('large.xz'));
LZMADataError — File is not XZ-compressed or is corrupted. Verify with file compressed.xz or xz -t compressed.xz.
Slow on multi-core — Enable threads: createXz({ threads: 0 }) (auto-detect cores).
High memory with concurrency — Use LZMAPool to limit simultaneous operations.
Build fails — Install Visual Studio Build Tools and set Python:
npm install --global windows-build-tools
npm config set python python3
Path issues — Use path.join() instead of hardcoded separators.
We'd love to hear from you! If you're using node-liblzma in production, a side project, or an interesting use case, feel free to open a discussion or drop a comment on this thread. It helps us understand how the library is used and prioritize features.
If you find one, feel free to contribute and post a new issue! PRs are accepted as well :)
If you compile with threads, you may see warnings about -Wmissing-field-initializers.
This is normal and does not prevent threading from being active and working.
Kudos to addaleax for helping out with C++ stuff!
This software is released under LGPL-3.0+.
FAQs
NodeJS wrapper for liblzma
The npm package node-liblzma receives a total of 216,268 weekly downloads. As such, node-liblzma popularity was classified as popular.
We found that node-liblzma demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.

Security News
NIST will stop enriching most CVEs under a new risk-based model, narrowing the NVD's scope as vulnerability submissions continue to surge.