zip.js: A Browser-First Zip Library That Handles Large Archives and Parallel Compression
Project brief: JavaScript library to zip and unzip files supporting parallel compression, web streams, zip64, split files, data encryption, and deflate64 decompression.
At a glance
- What is it?
- zip.js is a JavaScript library for reading and writing zip files in the browser, Node.js, and Deno, with support for Zip64, split files, encryption, and multi-core compression. It is a strong choice for applications that must handle archives larger than 4GB or stream data incrementally, but its worker-based architecture and API require careful configuration.
- Who is it for?
- Adopt zip.js if you need to create or read zip archives in a browser environment with files larger than 4GB, split archives, or encrypted entries, and if you are comfortable configuring web workers for bundlers like Vite or webpack. Do not use it if your project targets older browsers without Web Streams support, or if you need a minimal dependency with a synchronous API.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- gildas-lormeau/zip.js3,913 ★ · +38
| Repository | 2026-08-04 | 2026-11-14 |
|---|---|---|
| gildas-lormeau/zip.js | 3.9k | 3.9k |
38 Stars in the last 102 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
What Problem zip.js Solves and Who It Is For
zip.js addresses a specific gap in the JavaScript ecosystem: handling zip files that exceed the 4GB limit of the classic ZIP format. Many libraries stop at that boundary, but zip.js explicitly supports Zip64, which is the extension that allows archives larger than 4GB. It also handles split zip files, where an archive is broken into multiple parts. This makes it useful for applications that deal with large media exports, backup tools, or any client-side file processing where the user might upload or download a multi-gigabyte archive. The library is designed for browsers first, but the README shows imports for Deno and the package is available on npm, so it also works in Node.js environments. The intended audience is developers building web applications that need to create or extract zip files without sending data to a server, and who need features like streaming, encryption, or parallel compression.
How It Works: Streams, Workers, and Pluggable Compression
The core architecture of zip.js revolves around readers and writers. You create a `ZipWriter` and pass it a writer object, like `BlobWriter` or a `TransformStream`, and then add entries using reader objects such as `TextReader`, `BlobReader`, or `HttpReader`. This design allows data to flow incrementally, which is essential for large files because you do not need to hold the entire archive in memory. The library uses web workers to offload compression and decompression work off the main thread. The README shows that you can let zip.js create workers automatically, or you can create them yourself using the `new Worker(new URL("./zip-worker.js", import.meta.url))` pattern, which bundlers like Vite and webpack detect and bundle. Compression is pluggable: by default it uses native compression streams, but you can configure a custom engine, such as fflate, by providing fallback classes to `initWorker`. This is a significant architectural choice because it means the library's performance depends on the worker setup and the underlying compression implementation.
Getting Started: The Hello World Example and Streams API
The README provides a minimal example to write a zip file. You import `BlobReader`, `BlobWriter`, `TextReader`, `TextWriter`, `ZipReader`, and `ZipWriter` from `@zip.js/zip.js`. To create an archive, you instantiate a `BlobWriter`, then a `ZipWriter` with that writer, and call `add()` with a name and a reader. Finally, you call `close()` to finalize the archive. The code is straightforward: `const zipFileWriter = new BlobWriter(); const helloWorldReader = new TextReader("Hello world!"); const zipWriter = new ZipWriter(zipFileWriter); zipWriter.add("hello.txt", helloWorldReader); await zipWriter.close();`. There is also a streams-based version that uses a `TransformStream` to produce a `Blob` via `new Response(zipFileStream.readable).blob()`. This is useful when you want to pipe data directly to a download or a network request. The API is promise-based, so you need to await each operation. The README also shows how to add multiple entries concurrently using `Promise.all`, which leverages the parallel compression feature.
Parallel Compression and Custom Workers: The Real Power and the Real Complexity
One of the standout features is the ability to add multiple entries concurrently. The README example uses `Promise.all` with two `zipWriter.add()` calls, and the library handles the compression in parallel using web workers. This can significantly speed up archive creation on multi-core machines. However, this power comes with complexity. To use custom workers, you must configure the library with `configure({ createWorker: () => new Worker(new URL("./zip-worker.js", import.meta.url), { type: "module" }) })`. Then you need a separate `zip-worker.js` file that imports `initWorker` and provides fallback compression streams. This is not a zero-configuration setup. If you are using a bundler, you must ensure it supports the `new URL` pattern for worker bundling. If you are using a CDN or a simple script tag, you will need to handle worker paths manually. The documentation points to a complete guide, but the README itself makes it clear that this is an advanced topic. For many projects, the default worker creation might suffice, but the moment you need to customize compression, you inherit this configuration burden.
Limitations and Failure Modes: When zip.js Is the Wrong Tool
The most obvious limitation is the reliance on web workers and modern stream APIs. If your target browsers do not support `TransformStream` or `ReadableStream` (older Safari versions, for example), you will need polyfills or fallbacks, and the library's streaming benefits diminish. The README mentions `CompressionStreamFallback` and `DecompressionStreamFallback` for custom engines, but that implies you must provide these fallbacks yourself if you want compatibility. Another limitation is that the library is promise-based, which means you cannot use it in a synchronous context. If you have a Node.js script that needs to zip a file synchronously, this library will force you to restructure your code. Also, while zip.js supports encryption, the README does not specify which encryption algorithms are available. The description mentions "data encryption," but without further detail, you cannot assume it supports AES-256 or ZipCrypto. If you need a specific encryption standard, you must verify it in the full documentation. Finally, the library is designed for large data, but that does not mean it is memory-free. Streaming helps, but the `BlobWriter` still accumulates the entire archive in memory as a Blob, so a 10GB archive would still consume significant memory.
Alternatives: fflate and the Difference in Approach
The README itself mentions fflate as a custom compression engine, which is a good starting point for comparison. fflate is a standalone library that does not require web workers by default. It runs compression and decompression on the main thread, which is simpler to set up and works in environments where workers are not available or are too costly to manage. The trade-off is that fflate blocks the main thread during large operations, which can freeze the UI. zip.js offloads work to workers, keeping the main thread responsive, but at the cost of configuration complexity. Another difference is that fflate is a general-purpose compression library, while zip.js is specifically for zip files. If you only need to compress a single string or buffer, fflate is lighter. But if you need to handle zip archives with multiple entries, streaming, and Zip64, zip.js offers a higher-level API. The choice depends on whether you prioritize simplicity (fflate) or non-blocking performance for large archives (zip.js).
Maintenance, Licensing, and Upgrade Considerations
zip.js is licensed under BSD-3-Clause, which is permissive and allows commercial use with attribution. The repository is not archived, and the last push was in August 2026, with releases v2.8.61, v2.8.60, and v2.8.59 appearing in quick succession. This suggests active maintenance, but it also means frequent updates. You should expect to track releases for bug fixes and security patches. The README does not mention a migration guide or breaking changes between minor versions, so upgrading may require reading the changelog. The library's dependency on web workers and stream APIs means that browser updates could affect behavior, so you should test after browser updates as well. The cost of maintenance is not just updating the package; it is also ensuring your worker configuration remains correct across bundler versions. The README shows a specific pattern for Vite, webpack, and Rollup, but those tools evolve, and you may need to adjust your worker setup when upgrading your build stack.
Editorial conclusion
Adopt zip.js if you need to create or read zip archives in a browser environment with files larger than 4GB, split archives, or encrypted entries, and if you are comfortable configuring web workers for bundlers like Vite or webpack. Do not use it if your project targets older browsers without Web Streams support, or if you need a minimal dependency with a synchronous API. Before adoption, verify that your build tool correctly bundles the worker scripts using the documented `new Worker(new URL(...))` pattern, and test that your target browsers support the required stream APIs. The library is actively maintained, but the complexity of worker management and the promise-based API are real costs to plan for.
Frequently asked questions
How do I zip a file with zip.js?
Create a ZipWriter over a writer such as BlobWriter, add entries with a reader each, for example a TextReader for text or an HttpReader for a URL, and close the writer to get the content. Entries can be added in parallel by awaiting each add inside a Promise.all.
Is zip.js better than fflate?
They are not the same kind of thing. fflate is named in the zip.js readme as an example of a custom compression engine to which zip.js can delegate, wired in through a configure call and a worker init, so zip.js is the zip format layer and fflate is the compression underneath it.
Which runtimes does zip.js support?
The package describes itself as a library to zip and unzip files in the browser, Deno, and Node.js. The engines field declares Deno 1.0.0 or newer, Node 18.0.0 or newer, and Bun 0.7.0 or newer, and the examples note the Deno import specifier prefix.
What does the ZipFS API in zip.js change?
It stores entries in a tree instead of a flat list, needs a single import, infers the reader and writer from the data type, and reaches an entry by name. An entry name is a path, so a directory is created implicitly by adding a file under it.
How do I use a custom compression engine with zip.js?
Import configure from the dedicated custom core module and pass a createWorker callback, then initialise the worker with initWorker, supplying your engine's compression and decompression stream fallbacks. The readme names fflate as a worked example.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gildas-lormeau-zip-js)Star history chart for your README
[](https://hysenlabs.com/projects/gildas-lormeau-zip-js)Was this useful?