yauzl - Node.js Zip File Reader
yauzl (yet another unzip library) is a Node.js package designed for reading and extracting `.zip` archives. It strictly adheres to the ZIP specification, differentiating itself by reading the central directory for file metadata rather than scanning for local file headers, which are prone to being out of sync with the central directory. The library emphasizes non-blocking, asynchronous APIs and efficient memory usage, particularly through its `lazyEntries` option, which prevents buffering entire files or all entries into RAM simultaneously. Version 3.3.0 is the current stable release, with the project demonstrating a healthy and positive release cadence, with updates typically occurring every few months. Key differentiators include robust error handling, built-in validation to guard against unsafe file names and potential zip bomb attacks, and support for non-conformant zip files created by certain Microsoft tools. The API is callback-based, making it suitable for event-driven Node.js applications.
Common errors
-
JavaScript heap out of memory
cause `lazyEntries` option was `false`, leading to all entries being buffered or processed too quickly for large zip files or those with many small entries.fixSet `lazyEntries: true` when opening the zip file and manually call `zipfile.readEntry()` after each entry's data stream has finished processing. -
Error: Invalid or unsupported zip file. (End of Central Directory Record not found)
cause The input file is not a valid ZIP archive, or it's severely corrupted, preventing `yauzl` from locating the central directory.fixVerify that the input file is indeed a valid and uncorrupted `.zip` archive. Check file integrity or source. -
Error: Entry filename contains unsafe characters
cause `yauzl`'s `validateFileName()` detected characters or patterns (like absolute paths, `..` segments, or backslashes with `strictFileNames: true`) that are considered unsafe for extraction.fixInspect `entry.fileName`. If the name is genuinely unsafe, reject the entry. If backslashes are the issue and expected from non-conformant zips, ensure `strictFileNames: false` (the default) and `decodeStrings: true`. -
Error: Z_DATA_ERROR: incorrect header check
cause The zlib decompression stream encountered corrupted or invalid compressed data for a file entry.fixThis indicates a corruption within the zip file's contents for a specific entry. The zip file itself might be damaged. There is no code fix for a corrupted source file; you may need to acquire an uncorrupted archive. -
RangeError: Zip entry size mismatch
cause `validateEntrySizes` was `true` (default) and the actual uncompressed size of an entry did not match the size reported in the zip file's metadata, potentially indicating a zip bomb or corrupted data.fixHandle the error gracefully. This is a security feature. The zip file might be intentionally malicious or simply corrupted. Ensure `yauzl` is updated to the latest stable version to benefit from all fixes and validations.
Warnings
- breaking Version 3.0.0 introduced breaking changes, including dropping support for Node.js versions older than 12. Additionally, implementations of `RandomAccessReader` (for custom back-ends) must now implement a `_destroy` method instead of `destroy` to align with Node.js stream standards.
- breaking CVE-2026-31988: A denial of service vulnerability exists in `yauzl` version 3.2.0 due to an off-by-one error in a timestamp parser. Processing a specially crafted zip file could crash the Node.js process.
- gotcha The `lazyEntries` option defaults to `false`. While this allows piping file data from all entries in parallel, it can lead to excessive memory consumption for zip files containing many entries. For better memory control, especially with large archives, `lazyEntries: true` is highly recommended.
- gotcha The `validateEntrySizes` option defaults to `true` and ensures an entry's reported uncompressed size matches its actual size, which helps defend against zip bomb attacks. Disabling this option (setting it to `false`) removes this crucial validation, potentially exposing the application to exploits or unexpected behavior from malformed archives.
- gotcha The `strictFileNames` option defaults to `false`. This default behavior replaces backslashes (`\`) in `entry.fileName` with forward slashes (`/`), allowing `yauzl` to read non-conformant zip files created by some Microsoft tools. If `strictFileNames` is set to `true`, entries with backslashes will result in an error when `decodeStrings` is also `true`.
- gotcha The `decodeStrings` option defaults to `true`, causing `yauzl` to decode filenames and comments using CP437 or UTF-8. If set to `false`, `entry.fileName`, `entry.fileComment`, and `zipfile.comment` will be `Buffer` objects instead of strings, and automatic filename validation (via `validateFileName()`) will be bypassed.
Install
-
npm install yauzl -
yarn add yauzl -
pnpm add yauzl
Imports
- yauzl
const yauzl = require('yauzl'); // CommonJS in ESM context without adapterimport yauzl from 'yauzl';
- open
import { open } from 'yauzl'; // Not a named export for the main function.import yauzl from 'yauzl'; yauzl.open(...);
- ZipFile
import { ZipFile } from 'yauzl'; // Not a named exportimport yauzl from 'yauzl'; // Access ZipFile class via yauzl.ZipFile
Quickstart
import * as fs from 'fs';
import * as path from 'path';
import yauzl from 'yauzl';
const zipFilePath = 'path/to/your/archive.zip';
const extractDir = 'path/to/extract/to';
fs.mkdirSync(extractDir, { recursive: true });
yauzl.open(zipFilePath, { lazyEntries: true, autoClose: true }, (err, zipfile) => {
if (err) throw err;
zipfile.on('entry', (entry) => {
const entryPath = path.join(extractDir, entry.fileName);
if (//$/.test(entry.fileName)) {
// Directory file names end with '/'
fs.mkdirSync(entryPath, { recursive: true });
zipfile.readEntry();
} else {
// File entry
zipfile.openReadStream(entry, (err, readStream) => {
if (err) throw err;
readStream.on('end', () => {
zipfile.readEntry();
});
// Ensure parent directory exists for the file
fs.mkdirSync(path.dirname(entryPath), { recursive: true });
readStream.pipe(fs.createWriteStream(entryPath));
});
}
});
zipfile.on('end', () => {
console.log('Zip extraction complete.');
});
// Start reading entries
zipfile.readEntry();
});