node-unzipper
A streaming zip extraction library for Node.js that supports random access to files on disk, in buffers, over HTTP, or on S3 without buffering the whole archive.
Repository Health
Technical Analysis
unzipper is a cross-platform, streaming zip-handling library for Node.js built entirely on the platform’s built-in zlib and stream modules, with no compiled native dependencies. It began as a fork of node-unzip and now offers two complementary APIs: a legacy streaming Parse/Extract interface that processes a zip file sequentially as it arrives, and a newer Open interface that reads the zip’s central directory first and then grants random access to individual files inside it.
The Open methods (Open.file, Open.buffer, Open.url, Open.s3, Open.s3_v3, Open.custom) are the more distinctive part of the library: each accepts a source capable of returning byte ranges and a total size, then locates the end-of-central-directory record using only the tail bytes of the archive. This lets a caller extract a single file out of a multi-hundred-megabyte zip hosted remotely by issuing HTTP range requests or S3 range GETs, never downloading the full archive. The legacy Parse path remains useful for straightforward local extraction and for piping zip entries into transform streams.
Because it’s a long-lived project (first released in 2016, still receiving regular commits), it has accumulated support for edge cases like zip64 extended fields, CRX (Chrome extension) headers, password-encrypted entries via Decrypt.js, and non-UTF8 filename encodings from legacy DOS/Windows zip tools.
What You Get
- Sequential streaming API (
Parse,ParseOne,Extract) for piping a zip file’s contents through Node streams as they arrive - Random-access
OpenAPI (Open.file,Open.buffer,Open.url,Open.s3,Open.s3_v3,Open.custom) that reads only the central directory plus the requested file’s bytes - Support for password-protected/encrypted zip entries via a built-in decryption module
- Handling for zip64 extended fields, CRX (Chrome extension) archive headers, and non-Unicode legacy filename encodings
- A pluggable custom-source interface so any byte-range-capable backend (e.g. Google Cloud Storage) can be wired into the
OpenAPI - Dual ESM/CommonJS build output, so it can be required or imported depending on the consumer’s module system
Common Use Cases
- Extracting a single known file out of a very large zip archive hosted remotely, without downloading the whole thing
- Streaming-unzipping an uploaded zip file directly to disk or to another stream-based pipeline (e.g. an ETL transform)
- Reading zip archives stored in S3 or S3-compatible object storage using HTTP range requests
- Parsing zip files produced by legacy DOS/Windows tools that use non-UTF8 filename encoding
- Unpacking Chrome extension (.crx) packages, which are zip files with an extra header
Under The Hood
Architecture
unzipper splits cleanly into two independent pipelines that share low-level primitives. The legacy path (lib/parse.js) implements a Parser as a Node Duplex stream that reads local file header signatures (0x04034b50), central directory signatures (0x02014b50), and the end-of-central-directory signature (0x06054b50) off a custom PullStream (lib/PullStream.js), emitting entry events or pushing parsed entries downstream when piped. The Open path (lib/Open/index.js + lib/Open/directory.js) instead wraps an abstract source object exposing stream(offset, length) and size(), reads only the tail of the archive to locate the end-of-central-directory record (configurable via a tailSize option, default 80 bytes), and returns a files array whose entries expose stream()/buffer() for on-demand random access — this is what lets Open.url and Open.s3 avoid downloading the entire archive. PullStream itself is the shared abstraction underneath both paths: a Duplex that buffers incoming bytes and lets callers pull(eof) either a fixed byte count or up-to-a-signature-match, which both the sequential parser and the central-directory reader build on. Swapping the core PullStream buffering strategy would ripple through both APIs since neither has an alternate low-level read path.
Tech Stack
The library ships as native ESM ("type": "module", index.js) with a parallel CommonJS build (index.cjs, generated at publish time via a Babel-based build-commonjs script and a small scripts/create-commonjs-package-json.cjs helper) so it’s consumable from either module system. Zip inflation itself uses Node’s built-in zlib, and file-system access goes through graceful-fs rather than the raw fs module to better tolerate EMFILE/ENFILE errors on busy systems. Runtime dependencies are intentionally small: bluebird (promise utilities in older code paths), duplexer2 (composing duplex streams), fs-extra, graceful-fs, and node-int64 (for zip64 64-bit offsets that exceed JS’s safe integer range). Optional integrations — request for Open.url, aws-sdk/@aws-sdk/client-s3 for Open.s3/Open.s3_v3 — are consumer-supplied peer-style dependencies rather than bundled ones, so applications only pull them in if they use those specific Open methods. CI runs on GitHub Actions with separate test.yml, coverage.yml, and publish.yml workflows.
Code Quality
Testing uses tap with coverage thresholds enforced in package.json scripts (--lines=90 --functions=85 --statements=90 --branches=80), and the suite is run twice — once against the native ESM build (test-esm) and once against a Babel-transpiled CommonJS build (test-esm-transpiled) plus a dedicated test-commonjs suite — to guard both distribution targets. The test/ directory covers a wide range of scenarios beyond the happy path: zip64 archives, CRX headers, broken/corrupt zips, chunk-boundary edge cases, encrypted files, S3 (both SDK v2 and v3 clients), custom sources, and zip-slip path-traversal protection (zipSlipSiblingPrefix.js). ESLint is configured with a small custom ruleset (no-var, prefer-const, enforced semicolons/indentation) on top of @eslint/js recommended rules. Error handling is mostly done through stream error events and rejected promises rather than typed exceptions (there’s no TypeScript here, and no static types), and some internal comments (e.g. in PullStream.js) note inherited code whose original rationale wasn’t fully understood by later maintainers — a sign of accumulated legacy behavior rather than a from-scratch design.
API Design
The library’s two APIs are pitched at different levels of ergonomics. The streaming Parse/Extract API mirrors Node’s own stream idioms closely (.pipe(), entry events, .autodrain() to discard unwanted entries, async-iterator support via for await), which keeps the learning curve low for anyone already comfortable with Node streams — though it does require callers to remember to drain or consume every entry or the stream stalls. The Open API trades that familiarity for a promise-based random-access model (await unzipper.Open.file(...), then directory.files[0].stream()/.buffer()) that’s more convenient for one-off extraction but requires understanding a different mental model (central directory vs. sequential parse). Documentation is thorough for a project this size — the README walks through every open method, S3 v2 vs v3 usage, custom source implementation, and legacy-encoding handling with runnable examples — though some newer usage (e.g. Open.custom) is documented only by example rather than a full API reference.
Used by 12 apps in this directory
Bun
Developer Tools
An all-in-one JavaScript and TypeScript toolkit — one Rust-and-JavaScriptCore binary that replaces Node.js, npm, a bundler, and a test runner with faster equivalents.
Jan
AI Assistants
Run LLMs 100% locally with full privacy, or connect to cloud AI — your machine, your data, your control.
Medplum
Developer Tools · Databases · Authentication
An open-source, FHIR-native healthcare platform that gives developers a compliant backend, authentication, a React component library, and serverless bots to build clinical applications in weeks instead of years.
nango
Developer Tools · Automation · Authentication
Build product integrations with AI using 800+ APIs — auth, proxy, and TypeScript functions on production-grade infrastructure.
OpenPanel
Analytics
Open-source Mixpanel alternative with session replay, MCP integration, and privacy-first product analytics you fully control.
OpenWhispr
Productivity · AI Assistants
Privacy-first, cross-platform voice-to-text with local AI and cloud options
superglue
AI Agents · Data Engineering · Developer Tools
superglue is an AI-agent-driven integration engine that turns plain-English descriptions of enterprise systems into production-grade API tools, ERP/CRM connectors, and data pipelines — self-hosted or cloud, Y Combinator-backed (W25).
tau
Devops
Open-source, Git-native platform-as-a-service for building, deploying, and scaling fullstack apps on your own infrastructure with no DevOps required.
Teable
Databases · No Code Platforms
A no-code PostgreSQL database with spreadsheet UX, real-time collaboration, and native AI agents — built for teams that outgrow Airtable.