adm-zip vs node-zip vs yazl vs zip-a-folder vs zip-lib
Creating and Extracting Zip Archives in Node.js
adm-zipnode-zipyazlzip-a-folderzip-libSimilar Packages:

Creating and Extracting Zip Archives in Node.js

These five packages provide solutions for handling ZIP archives within the Node.js runtime. adm-zip is the most widely adopted pure JavaScript library for synchronous zip and unzip operations. yazl focuses on asynchronous zip creation with stream support. node-zip is a legacy package that is no longer maintained. zip-a-folder and zip-lib serve as higher-level utilities that wrap core libraries to simplify common tasks like compressing directories or handling promise-based workflows.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
adm-zip02,161122 kB14425 days agoMIT
node-zip0217-2011 years ago-
yazl037458.7 kB19a year agoMIT
zip-a-folder076212 kB011 days agoMIT
zip-lib04370.2 kB113 days agoMIT

Creating and Extracting Zip Archives in Node.js: A Technical Comparison

Handling compressed archives is a common requirement in backend development, from deploying artifacts to generating user downloads. The Node.js ecosystem offers several options, but they differ significantly in maintenance status, API design, and performance characteristics. This analysis compares adm-zip, node-zip, yazl, zip-a-folder, and zip-lib to help you select the right tool for your architecture.

šŸ›‘ Maintenance and Stability Status

Before comparing features, we must address the longevity of these packages. Using an unmaintained library in a production build pipeline introduces security risks and compatibility issues.

adm-zip is actively maintained and widely trusted. It has no native dependencies, making it easy to deploy across different environments.

node-zip is deprecated. The repository is archived, and it has not received updates in years. It should not be used in new projects.

// node-zip: Deprecated API pattern
const Zip = require('node-zip');
const zip = new Zip();
// WARNING: No longer receiving security patches

yazl is stable and maintained, focusing specifically on writing zips. It is often paired with yauzl for reading.

zip-a-folder and zip-lib are smaller utilities. zip-a-folder wraps adm-zip, while zip-lib offers a promise-based interface. Check their recent commit history before adopting for critical paths.

// zip-lib: Check maintenance status
const zipLib = require('zip-lib');
// Verify last update before relying on this in production

āš™ļø API Design: Synchronous vs Asynchronous

The most significant technical difference lies in how these libraries handle I/O. Blocking the event loop can degrade server performance under load.

adm-zip uses a synchronous API. This simplifies code flow but blocks the Node.js event loop during compression or extraction.

// adm-zip: Synchronous execution
const AdmZip = require('adm-zip');
const zip = new AdmZip();
zip.addLocalFolder("./dist");
zip.writeZip("./archive.zip"); // Blocks thread until complete

yazl uses streams and callbacks. This allows non-blocking operations, which is critical for high-concurrency servers.

// yazl: Asynchronous stream
const yazl = require("yazl");
const zipFile = new yazl.ZipFile();
zipFile.addFile("./index.html", "index.html");
zipFile.end();
zipFile.outputStream.pipe(fs.createWriteStream("archive.zip"));

zip-lib wraps operations in Promises. This enables clean async/await syntax without manual stream management.

// zip-lib: Promise-based
const zipLib = require('zip-lib');
await zipLib.zip('./dist', './archive.zip'); // Returns a promise

zip-a-folder abstracts the process into a single function call, usually returning a promise or accepting a callback.

// zip-a-folder: High-level abstraction
const zipFolder = require('zip-a-folder');
await zipFolder('./src', './output.zip');

node-zip used a callback-based async model but is now obsolete.

// node-zip: Legacy callback style
zip.generate(function (err, data) {
  if (err) throw err;
  // Handle buffer
});

šŸ“‚ Zipping Directories and Files

Developers often need to compress entire folders. The effort required varies between packages.

adm-zip provides a dedicated method for local folders. It handles recursion automatically.

// adm-zip: Direct folder support
const zip = new AdmZip();
zip.addLocalFolder("./project/dist", "dist");
zip.writeZip("./build.zip");

yazl does not have a built-in "add folder" method. You must walk the directory tree yourself and add files individually.

// yazl: Manual file iteration
const files = getAllFilesRecursive("./dist");
files.forEach(f => zipFile.addFile(f, path.relative("./dist", f)));
zipFile.end();

zip-a-folder is designed specifically for this task. It requires the least amount of code.

// zip-a-folder: One-line folder zip
await zipFolder("./project/dist", "./build.zip");

zip-lib also supports directory zipping via its main function.

// zip-lib: Directory support
await zipLib.zip("./project/dist", "./build.zip");

node-zip required manual buffer management for multiple files, adding complexity.

// node-zip: Manual buffer handling
zip.file("index.html", fs.readFileSync("index.html"));

šŸ“„ Extraction and Reading Archives

Not all libraries support unzipping. Some are write-only, which impacts architectural choices.

adm-zip supports both reading and writing. You can extract all contents or specific entries.

// adm-zip: Full extraction
const zip = new AdmZip("./archive.zip");
zip.extractAllTo("./output", true); // true = overwrite

yazl is write-only. To unzip, you must install a companion library like yauzl. This separation of concerns can be beneficial for bundle size.

// yazl: Cannot unzip (Write-only)
// Must use yauzl for extraction instead

zip-lib supports both operations via distinct methods.

// zip-lib: Extract method
await zipLib.unzip("./archive.zip", "./output");

zip-a-folder is primarily focused on creating zips from folders. Extraction is not its main focus and may require other tools.

// zip-a-folder: Limited extraction support
// Primarily designed for zipping folders, not extracting

node-zip supported reading but is no longer safe to use for this purpose.

// node-zip: Legacy reading
zip.load(data);
const file = zip.file("index.html");

šŸš€ Performance and Memory Usage

Memory management is critical when handling large archives. Loading entire files into memory can crash a process.

adm-zip loads the archive into memory. For very large files (hundreds of MBs), this can cause high memory pressure.

// adm-zip: In-memory operation
// Caution with large files:
const zip = new AdmZip("./large-file.zip"); // Loads fully into RAM

yazl streams data. It does not need to hold the entire archive in memory, making it safer for large outputs.

// yazl: Stream-friendly
// Data flows through without loading everything into RAM
zipFile.addReadStream(fs.createReadStream("large-file.bin"), "large-file.bin");

zip-lib typically uses streams under the hood but exposes a promise interface. Check documentation for large file limits.

// zip-lib: Promise wrapper over streams
await zipLib.zip("./large-folder", "./large.zip");

zip-a-folder relies on adm-zip internally, so it inherits the memory characteristics of adm-zip.

// zip-a-folder: Inherits adm-zip memory behavior
// Watch memory usage on large directories

node-zip had similar memory constraints but lacks modern optimizations.

// node-zip: Older memory handling
// No modern stream optimizations available

šŸ“Š Summary Comparison

Featureadm-zipnode-zipyazlzip-a-folderzip-lib
Statusāœ… ActiveāŒ Deprecatedāœ… Activeāš ļø Wrapperāš ļø Niche
API StyleSyncAsync (Legacy)Async StreamAsync/SyncPromise
Read/WriteBothBothWrite OnlyWrite FocusBoth
MemoryHigh (In-memory)HighLow (Stream)HighMedium
ComplexityLowLowMediumVery LowLow

šŸ’” Architectural Recommendation

For most backend services and build tools, adm-zip remains the default choice. Its synchronous API is easier to reason about in scripts, and its read/write support covers all bases. The memory trade-off is acceptable for typical build artifacts.

For web servers generating dynamic downloads, yazl is superior. Streaming prevents memory spikes when multiple users request large files simultaneously. Remember to pair it with yauzl if you also need to read archives.

Avoid node-zip entirely. The risk of security vulnerabilities outweighs any familiarity benefits. Migrate existing code to adm-zip as soon as possible.

Use zip-a-folder for simple CLI utilities where development speed matters more than fine-grained control. Use zip-lib if your team strictly enforces promise-based patterns and finds adm-zip's synchronous style inconsistent with your codebase.

šŸ”’ Security Considerations

When extracting archives, always validate paths to prevent Zip Slip vulnerabilities. adm-zip has had patches for this, but you must still ensure target paths are safe.

// Security check example for any library
const path = require('path');
const target = path.resolve("./output", entryName);
if (!target.startsWith(path.resolve("./output"))) {
  throw new Error("Invalid path");
}

Regardless of the library, never extract user-uploaded zips without validating the contents. This protects your server from writing files to unauthorized locations.

How to Choose: adm-zip vs node-zip vs yazl vs zip-a-folder vs zip-lib

  • adm-zip:

    Choose adm-zip for most server-side tasks where synchronous operations are acceptable. It is the industry standard for reading and writing zip files in Node.js without native dependencies. It is ideal for build scripts, artifact generation, and simple file manipulation where blocking the event loop briefly is not a concern.

  • node-zip:

    Do NOT choose node-zip for new projects. It is deprecated and unmaintained. Existing projects using it should plan a migration to adm-zip or yazl to ensure security updates and compatibility with modern Node.js versions.

  • yazl:

    Choose yazl when you need to create zip files asynchronously or stream data directly into an archive. It is perfect for web servers that generate downloads on the fly without writing intermediate files to disk. It does not support unzipping, so pair it with yauzl if extraction is needed.

  • zip-a-folder:

    Choose zip-a-folder for quick CLI tools or scripts where you only need to compress a directory into a single file. It abstracts away the setup required by adm-zip. Avoid it for complex archive manipulation where you need fine-grained control over individual entries.

  • zip-lib:

    Choose zip-lib if you prefer a promise-based API for both zipping and unzipping without managing streams manually. It is suitable for modern async/await codebases that need a cleaner interface than adm-zip offers, though it may have a smaller community ecosystem.

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