adm-zip vs jszip vs node-zip vs zip-stream
Handling ZIP Archives in JavaScript Applications
adm-zipjszipnode-zipzip-streamSimilar Packages:

Handling ZIP Archives in JavaScript Applications

adm-zip, jszip, node-zip, and zip-stream are libraries used to create, read, and extract ZIP archives in JavaScript. jszip is universal, working in both browsers and Node.js with an async API. adm-zip is designed for Node.js only and uses a synchronous approach for direct file system access. zip-stream provides a streaming interface for Node.js, ideal for large files or piping data. node-zip is a legacy package that is no longer maintained and should be avoided in new projects.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
adm-zip02,159122 kB1435 days agoMIT
jszip010,331762 kB410-(MIT OR GPL-3.0-or-later)
node-zip0217-2011 years ago-
zip-stream01679.33 kB27a year agoMIT

Handling ZIP Archives in JavaScript: adm-zip vs jszip vs node-zip vs zip-stream

Creating and extracting ZIP files is a common need in web development, whether for downloading multiple assets, backing up data, or processing uploads. The JavaScript ecosystem offers several tools for this, but they differ significantly in where they run, how they handle data, and their current maintenance status. Let's compare how they tackle common problems.

🌍 Environment Support: Where Code Runs

jszip works everywhere.

  • It runs in modern browsers and Node.js environments.
  • Ideal for client-side features like exporting data directly from a web app.
// jszip: Universal support
const JSZip = require("jszip");
const zip = new JSZip();
// Works in browser console or Node.js script

adm-zip is Node.js only.

  • It relies on the Node.js file system module.
  • Cannot be bundled for frontend use without polyfills or shims.
// adm-zip: Node.js only
const AdmZip = require("adm-zip");
const zip = new AdmZip();
// Will fail in a browser environment

zip-stream is Node.js only.

  • It is built on Node.js streams.
  • Designed for server-side piping and large file handling.
// zip-stream: Node.js only
const ZipStream = require("zip-stream");
const output = fs.createWriteStream("archive.zip");
// Requires Node.js stream APIs

node-zip was Node.js only.

  • It was built for older Node.js versions.
  • No longer compatible with modern runtime expectations.
// node-zip: Legacy Node.js
const zip = require("node-zip");
// Deprecated and unsupported in modern environments

βš™οΈ Execution Model: Sync vs Async vs Stream

adm-zip is synchronous.

  • Operations block the event loop until finished.
  • Simple to write but can freeze UI or server if files are large.
// adm-zip: Synchronous
zip.addFile("test.txt", Buffer.from("hello"));
zip.writeZip("output.zip"); // Blocks execution here

jszip is asynchronous.

  • Uses Promises for generating and loading archives.
  • Keeps the application responsive during processing.
// jszip: Asynchronous
zip.file("test.txt", "hello");
const content = await zip.generateAsync({ type: "blob" }); // Non-blocking

zip-stream is streaming.

  • Processes data in chunks as it flows through pipes.
  • Memory efficient for very large archives.
// zip-stream: Streaming
const archive = new ZipStream();
archive.pipe(output);
archive.entry("test.txt", { name: "test.txt" });
archive.finalize(); // Ends the stream

node-zip used callbacks.

  • Relied on older Node.js callback patterns.
  • Harder to manage than modern Promises or async/await.
// node-zip: Callback-based
zip.load(data, function(err, result) {
  // Handle result or error in callback
});

πŸ“¦ Creating Archives: API Comparison

The way you add files and save the archive varies greatly between these libraries.

adm-zip uses direct file paths or buffers.

  • You add files immediately and write to disk synchronously.
// adm-zip: Add and write
const zip = new AdmZip();
zip.addFile("file.txt", Buffer.from("content"));
zip.writeZip("./archive.zip");

jszip chains file additions and generates asynchronously.

  • You define the structure first, then generate the output.
// jszip: Chain and generate
const zip = new JSZip();
zip.file("file.txt", "content");
zip.generateAsync({ type: "nodebuffer" }).then((content) => {
  fs.writeFile("archive.zip", content);
});

zip-stream pipes entries into a stream.

  • You must manage the stream lifecycle and piping manually.
// zip-stream: Pipe entries
const archive = new ZipStream();
archive.pipe(fs.createWriteStream("archive.zip"));
archive.entry(fs.createReadStream("file.txt"), { name: "file.txt" });
archive.finalize();

node-zip required loading data first.

  • You often had to load binary data before manipulating it.
// node-zip: Load and modify
const zip = new Zip();
zip.load(binaryData, function(err) {
  zip.files["file.txt"] = "content";
});

πŸ“‚ Reading and Extracting Files

Extraction logic also differs based on the execution model.

adm-zip extracts directly to the file system.

  • One command unpacks the whole archive to a folder.
// adm-zip: Extract to folder
const zip = new AdmZip("archive.zip");
zip.extractAllTo("./output", true);

jszip returns files as objects or blobs.

  • You decide where to save or how to process the content.
// jszip: Read content
JSZip.loadAsync(data).then((zip) => {
  zip.file("file.txt").async("string").then((text) => {
    console.log(text);
  });
});

zip-stream is primarily for creation.

  • It does not support extraction; use unzip-stream instead.
  • Focused on output rather than input.
// zip-stream: Creation only
// No extraction API available in this package
// Developers must use a separate library for unpacking

node-zip allowed reading via callbacks.

  • Required manual iteration over file entries.
// node-zip: Read entries
zip.files.forEach(function(entry) {
  // Process entry data manually
});

⚠️ Maintenance Status

jszip is actively maintained.

  • Regular updates for security and performance.
  • Safe for production use in critical applications.

adm-zip is actively maintained.

  • Stable API with occasional updates for Node compatibility.
  • Reliable for backend scripting tasks.

zip-stream is maintained but low-level.

  • Often updated via the archiver ecosystem.
  • Stable for streaming use cases.

node-zip is deprecated.

  • Marked as deprecated on npm.
  • Should not be used in new projects under any circumstances.

πŸ“Š Summary Table

Featureadm-zipjszipzip-streamnode-zip
EnvironmentNode.jsBrowser + NodeNode.jsNode.js (Legacy)
ModelSynchronousAsynchronousStreamingCallback
Extractionβœ… Yesβœ… Yes❌ Noβœ… Yes
Statusβœ… Activeβœ… Activeβœ… Active❌ Deprecated
Best ForCLI ToolsWeb AppsLarge FilesNone

πŸ’‘ The Big Picture

jszip is like a universal adapter πŸ”Œ β€” great for teams that need one library to work across frontend and backend. Ideal for web apps, user downloads, and moderate-sized data processing.

adm-zip is like a heavy-duty tool πŸ› οΈ β€” perfect for Node.js scripts that need quick, synchronous access to the file system. Shines in CLI tools and backend automation where simplicity matters.

zip-stream is like a conveyor belt 🏭 β€” best for servers handling large files where memory usage is a concern. Use this when you need to pipe data directly without buffering everything.

node-zip is like an old machine 🏚️ β€” it used to work, but parts are no longer available. Do not use it. Migrate to jszip or adm-zip to keep your stack secure.

Final Thought: Despite their differences, all these libraries aim to handle compression standards. Choose based on your environment and data size. For most modern web work, jszip is the safest bet. For Node-only heavy lifting, adm-zip or zip-stream will serve you better.

How to Choose: adm-zip vs jszip vs node-zip vs zip-stream

  • adm-zip:

    Choose adm-zip if you are building a Node.js CLI tool or backend script that needs to synchronously read or write ZIP files to the local disk. It is straightforward for simple tasks where blocking the event loop is acceptable. Avoid it for browser applications or high-concurrency servers where async operations are required.

  • jszip:

    Choose jszip if you need to handle ZIP files in the browser or require a non-blocking async API in Node.js. It is the best choice for web apps that let users download or upload archives without server involvement. It handles in-memory operations well, making it suitable for moderate-sized files.

  • node-zip:

    Do not choose node-zip for any new project. It is officially deprecated and no longer receives security updates or bug fixes. Existing projects using this library should plan a migration to jszip or adm-zip to ensure long-term stability and security.

  • zip-stream:

    Choose zip-stream if you are working in Node.js and need to stream large ZIP archives directly to a response or file without loading everything into memory. It is often used under the hood by higher-level tools like archiver. It is best for high-performance server tasks involving large data sets.

README for adm-zip

ADM-ZIP for NodeJS

ADM-ZIP is a pure JavaScript implementation for zip data compression for NodeJS.

Build Status

Installation

With npm do:

$ npm install adm-zip

Electron file system support described below.

What is it good for?

The library allows you to:

  • decompress zip files directly to disk or in memory buffers
  • compress files and store them to disk in .zip format or in compressed buffers
  • update content of/add new/delete files from an existing .zip

Dependencies

There are no other nodeJS libraries that ADM-ZIP is dependent of

Examples

Basic usage

var AdmZip = require("adm-zip");

// reading archives
var zip = new AdmZip("./my_file.zip");
var password = "1234567890";
var zipEntries = zip.getEntries(); // an array of ZipEntry records - add password parameter if entries are password protected

zipEntries.forEach(function (zipEntry) {
    console.log(zipEntry.toString()); // outputs zip entries information
    if (zipEntry.entryName == "my_file.txt") {
        console.log(zipEntry.getData().toString("utf8"));
    }
});
// outputs the content of some_folder/my_file.txt
console.log(zip.readAsText("some_folder/my_file.txt"));
// extracts the specified file to the specified location
zip.extractEntryTo(/*entry name*/ "some_folder/my_file.txt", /*target path*/ "/home/me/tempfolder", /*maintainEntryPath*/ false, /*overwrite*/ true);
// extracts everything
zip.extractAllTo(/*target path*/ "/home/me/zipcontent/", /*overwrite*/ true);

// creating archives
var zip = new AdmZip();

// add file directly
var content = "inner content of the file";
zip.addFile("test.txt", Buffer.from(content, "utf8"), "entry comment goes here");
// add local file
zip.addLocalFile("/home/me/some_picture.png");
// get everything as a buffer
var willSendthis = zip.toBuffer();
// or write everything to disk
zip.writeZip(/*target file name*/ "/home/me/files.zip");

// ... more examples in the wiki

For more detailed information please check out the wiki.

Electron original-fs

ADM-ZIP has supported electron original-fs for years without any user interractions but it causes problem with bundlers like rollup etc. For continuing support original-fs or any other custom file system module. There is possible specify your module by fs option in ADM-ZIP constructor.

Example:

const AdmZip = require("adm-zip");
const OriginalFs = require("original-fs");

// reading archives
const zip = new AdmZip("./my_file.zip", { fs: OriginalFs });
.
.
.