npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

node-liblzma

v3.1.2

Published

NodeJS wrapper for liblzma

Readme

Node-liblzma

NPM Version NPM Downloads CI Status Documentation License Node Version TypeScript npm provenance codecov code style: biome

Native Node.js bindings for liblzma — XZ/LZMA2 compression with browser support via WebAssembly.

Table of Contents

What is liblzma/XZ?

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.

Quick Start

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

What's New

v3.0.0 — Browser & WASM Support

Live Demo — Try XZ compression in your browser.

  • Browser/WASM support: Full XZ compression and decompression via WebAssembly
    • Same API as Node.js (xzAsync, unxzAsync, createXz, createUnxz)
    • WASM binary: ~52KB gzipped (under 100KB budget)
    • Web Streams API for streaming compression/decompression
    • Zero-config inline mode: import from 'node-liblzma/inline'
  • CLI tool (nxz): Portable xz-like command line tool
    • Full xz compatibility: -z, -d, -l, -k, -f, -c, -o, -v, -q
    • Compression presets 0-9 with extreme mode (-e)
    • tar.xz archive support: create, list, extract (compatible with system tar)
    • Progress display, stdin/stdout piping, benchmarking (-B)
  • tar-xz package: Create/extract .tar.xz archives — Node.js streaming + browser WASM
  • Progress events: Monitor compression/decompression in real-time
  • XZ Utils 5.8.x: Updated to latest stable version
  • 519 tests: Comprehensive test suite with 100% code coverage

v2.0.0 — TypeScript Modernization

  • Full TypeScript migration: Complete rewrite from CoffeeScript
  • Promise-based APIs: xzAsync() and unxzAsync()
  • Modern tooling: Vitest, Biome, pnpm, pre-commit hooks
  • Node.js >= 16 required (updated from >= 12)

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.

Browser Usage

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.

Basic Usage

// 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);
}

Streaming with Web Streams API

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 Modes

| 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);

Browser Limitations

  • No sync APIs: xzSync() / unxzSync() throw LZMAError in browsers
  • Presets 0-6 only: Presets 7-9 require more memory than WASM's 256MB limit
  • No filesystem: xzFile() / unxzFile() are not available
  • No Node Streams: Use createXz() / createUnxz() (Web TransformStream) instead of Xz / Unxz classes

Bundle Size

| 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.

CLI Tool (nxz)

This package includes nxz, a portable xz-like CLI tool that works on any platform with Node.js.

Installation

# Global installation (recommended for CLI usage)
npm install -g node-liblzma

# Then use directly
nxz --help

Quick Examples

# 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

tar.xz Archives

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.

All Options

| 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

Exit Codes

| Code | Meaning | |------|---------| | 0 | Success | | 1 | Error (file not found, format error, etc.) | | 130 | Interrupted (SIGINT/Ctrl+C) |

Ecosystem Packages

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 |

tar-xz — tar.xz archives

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);

nxz-cli — standalone CLI

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

API Reference

API Comparison with Zlib

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> |

Options

| 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.

Advanced Configuration

Thread Support

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.

Progress Monitoring

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.

Concurrency Control with LZMAPool

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);

File Compression Helpers

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.

Error Handling

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.

Buffer Size Optimization

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.

Async Callback Contract (errno-based)

The low-level native callback follows an errno-style contract matching liblzma behavior:

  • Signature: (errno: number, availInAfter: number, availOutAfter: number)
  • Success: errno is LZMA_OK or LZMA_STREAM_END
  • Error: any other errno value

High-level APIs remain ergonomic — Promise functions resolve to Buffer or reject with Error, stream users listen to error events.

Benchmark

Performance Hierarchy

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)

Full Comparison (246 KB source code, preset 6)

| 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 |

Native vs WASM (nxz -B, preset 6)

| 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

When to Use What

| 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 |

Installation

npm install node-liblzma
# or
pnpm add node-liblzma

System Libraries

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

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

Testing

pnpm test              # Run all 519 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.

Migration Guide

v1.x → v2.0

Breaking Changes

  1. Node.js >= 16 required (was >= 12)
  2. ESM module format (import instead of require)
  3. TypeScript source (CoffeeScript removed)

New Features

// 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');

Tooling Changes

  • Linter: Biome (replaces ESLint + Prettier)
  • Tests: Vitest (replaces Mocha)
  • Package Manager: pnpm recommended

Contributing

We welcome contributions! See the full contributing guidelines below.

Development Setup

git clone https://github.com/oorabona/node-liblzma.git
cd node-liblzma
pnpm install
pnpm build
pnpm test

Development Workflow

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

Pull Request Process

  1. Fork and create a feature branch (feat/, fix/, refactor/, docs/)
  2. Add tests for new functionality (100% coverage required)
  3. Run pnpm check:write && pnpm type-check && pnpm test
  4. Commit with conventional commits and push
  5. CI checks run automatically on PR

Troubleshooting

"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.

Related Projects

  • tar-xz — Create/extract tar.xz archives (powered by node-liblzma)
  • nxz-cli — Standalone CLI for XZ compression
  • lzma-purejs — Pure JavaScript LZMA implementation
  • node-xz — Node binding of XZ library
  • lzma-native — Complete XZ library bindings

Bugs

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.

Acknowledgements

Kudos to addaleax for helping out with C++ stuff!

License

This software is released under LGPL-3.0+.