zip-a-folder vs adm-zip vs archiver vs jszip vs node-zip vs zip-local
ZIPファイル操作
zip-a-folderadm-ziparchiverjszipnode-zipzip-local類似パッケージ:

ZIPファイル操作

ZIPファイル操作ライブラリは、Node.jsアプリケーション内でZIPファイルを作成、解凍、操作するためのツールを提供します。これらのライブラリは、ファイルやフォルダーを圧縮してZIP形式に変換したり、既存のZIPファイルからファイルを抽出したりする機能を持っています。これにより、データの転送や保存を効率化し、ストレージスペースを節約することができます。特に、ウェブアプリケーションやサーバーサイドアプリケーションでファイルのアップロードやダウンロードを行う際に便利です。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
zip-a-folder178,74976212 kB03日前MIT
adm-zip02,162122 kB14417日前MIT
archiver02,95043.1 kB1562年前MIT
jszip010,339762 kB410-(MIT OR GPL-3.0-or-later)
node-zip0217-2011年前-
zip-local012057.1 kB13--

機能比較: zip-a-folder vs adm-zip vs archiver vs jszip vs node-zip vs zip-local

ストリーミングサポート

  • zip-a-folder:

    zip-a-folderはストリーミング処理をサポートしていません。フォルダー全体を一度に圧縮するため、大きなフォルダーを扱う際にはメモリ使用量が増加します。

  • adm-zip:

    adm-zipはストリーミング処理をサポートしていません。すべてのファイルをメモリに読み込むため、大きなファイルやフォルダーを扱う際にはメモリ使用量が増加します。

  • archiver:

    archiverはストリーミングAPIを提供しており、大きなファイルやフォルダーを効率的に圧縮できます。データを逐次処理するため、メモリ使用量が少なく、パフォーマンスが向上します。

  • jszip:

    jszipはストリーミング処理をサポートしていませんが、ZIPファイルをメモリ内で操作します。大きなファイルを扱う際は、メモリ使用量に注意が必要です。

  • node-zip:

    node-zipはストリーミング処理をサポートしていません。ファイルをメモリに読み込んでから圧縮するため、大きなファイルを扱う際にはメモリ制限があります。

  • zip-local:

    zip-localはストリーミング処理をサポートしていません。ファイルをメモリに読み込んでから圧縮するため、大きなファイルを扱う際にはメモリ制限があります。

フォルダー圧縮

  • zip-a-folder:

    zip-a-folderはフォルダー全体を一度に圧縮することができます。フォルダーのパスを指定するだけで、再帰的にすべてのファイルとサブフォルダーを圧縮します。

  • adm-zip:

    adm-zipはフォルダーを再帰的に圧縮することができますが、フォルダー全体を一度に圧縮する機能はありません。フォルダー内のファイルを個別に圧縮する必要があります。

  • archiver:

    archiverはフォルダーを再帰的に圧縮することができ、サブフォルダーやファイルを含めて一度に圧縮できます。ストリーミング圧縮に対応しているため、大きなフォルダーの圧縮も効率的に行えます。

  • jszip:

    jszipはフォルダーを再帰的に圧縮することができますが、フォルダー全体を一度に圧縮する機能はありません。フォルダー内のファイルを個別に圧縮する必要があります。

  • node-zip:

    node-zipはフォルダーを再帰的に圧縮することができますが、フォルダー全体を一度に圧縮する機能はありません。フォルダー内のファイルを個別に圧縮する必要があります。

  • zip-local:

    zip-localはフォルダーを再帰的に圧縮することができますが、フォルダー全体を一度に圧縮する機能はありません。フォルダー内のファイルを個別に圧縮する必要があります。

ファイル解凍

  • zip-a-folder:

    zip-a-folderは解凍機能を提供していません。圧縮専用のライブラリです。

  • adm-zip:

    adm-zipはZIPファイルからファイルを解凍する機能を提供しています。特定のファイルを指定して解凍することも、全てのファイルを解凍することも可能です。

  • archiver:

    archiverは解凍機能を提供していません。圧縮専用のライブラリです。

  • jszip:

    jszipはZIPファイルからファイルを解凍する機能を提供しています。特定のファイルを指定して解凍することも、全てのファイルを解凍することも可能です。

  • node-zip:

    node-zipはZIPファイルからファイルを解凍する機能を提供しています。特定のファイルを指定して解凍することも、全てのファイルを解凍することも可能です。

  • zip-local:

    zip-localはZIPファイルからファイルを解凍する機能を提供しています。特定のファイルを指定して解凍することも、全てのファイルを解凍することも可能です。

APIのシンプルさ

  • zip-a-folder:

    zip-a-folderは非常にシンプルなAPIを提供しており、フォルダーを圧縮する作業が簡単に行えます。

  • adm-zip:

    adm-zipはシンプルで直感的なAPIを提供しており、特に小規模なプロジェクトや簡単なZIP操作に適しています。

  • archiver:

    archiverはストリーミングAPIを提供していますが、やや複雑なため、大規模なプロジェクトや専門的な用途に適しています。

  • jszip:

    jszipはシンプルで使いやすいAPIを提供しており、特にクライアントサイドでのファイル操作に強みがあります。

  • node-zip:

    node-zipはシンプルで直感的なAPIを提供しており、特に小規模なプロジェクトに適しています。

  • zip-local:

    zip-localはシンプルで直感的なAPIを提供しており、特にローカル環境でのファイル操作に特化しています。

Ease of Use: Code Examples

  • zip-a-folder:

    zip-a-folderを使用したフォルダーの圧縮の例

    const { zip } = require('zip-a-folder');
    
    zip('myFolder', 'example.zip').then(() => {
      console.log('フォルダーが圧縮されました。');
    });
    
  • adm-zip:

    adm-zipを使用したZIPファイルの作成と解凍の例

    const AdmZip = require('adm-zip');
    
    // ZIPファイルの作成
    const zip = new AdmZip();
    zip.addFile('hello.txt', Buffer.from('Hello, World!'));
    zip.addLocalFolder('myFolder');
    zip.writeZip('example.zip');
    
    // ZIPファイルの解凍
    const zipFile = new AdmZip('example.zip');
    zipFile.extractAllTo('outputFolder', true);
    
  • archiver:

    archiverを使用したストリーミングZIPファイルの作成の例

    const fs = require('fs');
    const archiver = require('archiver');
    
    const output = fs.createWriteStream('example.zip');
    const archive = archiver('zip');
    
    output.on('close', () => {
      console.log(`ZIPファイルが作成されました: ${archive.pointer()} バイト`);
    });
    
    archive.pipe(output);
    archive.append('Hello, World!', { name: 'hello.txt' });
    archive.directory('myFolder/', 'myFolder');
    archive.finalize();
    
  • jszip:

    jszipを使用したZIPファイルの作成と解凍の例

    const JSZip = require('jszip');
    const fs = require('fs');
    
    const zip = new JSZip();
    zip.file('hello.txt', 'Hello, World!');
    zip.folder('myFolder').file('file.txt', 'This is a file.');
    
    zip.generateAsync({ type: 'nodebuffer' }).then((content) => {
      fs.writeFileSync('example.zip', content);
      console.log('ZIPファイルが作成されました。');
    
      // ZIPファイルの解凍
      const unzip = new JSZip();
      fs.readFile('example.zip', (err, data) => {
        unzip.loadAsync(data).then((zip) => {
          zip.file('hello.txt').async('string').then((content) => {
            console.log(content); // 'Hello, World!'
          });
          zip.folder('myFolder').file('file.txt').async('string').then((content) => {
            console.log(content); // 'This is a file.'
          });
        });
      });
    });
    
  • node-zip:

    node-zipを使用したZIPファイルの作成と解凍の例

    const zip = require('node-zip')();
    const fs = require('fs');
    
    // ZIPファイルの作成
    zip.file('hello.txt', 'Hello, World!');
    zip.folder('myFolder').file('file.txt', 'This is a file.');
    const data = zip.generate({ base64: false });
    fs.writeFileSync('example.zip', data, 'binary');
    
    // ZIPファイルの解凍
    const unzip = require('node-zip')();
    const zipData = fs.readFileSync('example.zip', 'binary');
    unzip.load(zipData);
    console.log(unzip.files['hello.txt'].data.toString()); // 'Hello, World!'
    console.log(unzip.files['myFolder/file.txt'].data.toString()); // 'This is a file.'
    
  • zip-local:

    zip-localを使用したZIPファイルの作成と解凍の例

    const zipLocal = require('zip-local');
    const fs = require('fs');
    
    // ZIPファイルの作成
    zipLocal.zip('myFolder', (err, zip) => {
      if (err) throw err;
      zip.save('example.zip', () => {
        console.log('ZIPファイルが作成されました。');
    
        // ZIPファイルの解凍
        zip.extract('outputFolder', () => {
          console.log('ZIPファイルが解凍されました。');
        });
      });
    });
    

選び方: zip-a-folder vs adm-zip vs archiver vs jszip vs node-zip vs zip-local

  • zip-a-folder:

    zip-a-folderは、フォルダー全体を簡単にZIPファイルに圧縮するためのライブラリです。シンプルなインターフェースで、フォルダーのパスを指定するだけで圧縮が完了します。特に、フォルダー単位での圧縮作業が多いプロジェクトに便利です。

  • adm-zip:

    adm-zipは、シンプルで使いやすいAPIを提供し、特に小規模なプロジェクトや簡単なZIP操作に適しています。ファイルの圧縮、解凍、リスト表示が簡単に行えますが、大規模なデータセットやストリーミング処理には向いていません。

  • archiver:

    archiverは、ストリーミングAPIを提供し、大規模なファイルやフォルダーを効率的に圧縮できます。メモリ使用量が少なく、パフォーマンスが高いため、プロダクション環境に適しています。特に、リアルタイムでデータを圧縮しながら送信するアプリケーションに最適です。

  • jszip:

    jszipは、ブラウザとNode.jsの両方で動作するZIPファイル操作ライブラリです。ZIPファイルの作成、解凍、編集が可能で、特にクライアントサイドでのファイル操作に強みがあります。インターフェースが直感的で、ファイルをプログラムmatically追加したり、抽出したりするのが簡単です。

  • node-zip:

    node-zipは、シンプルなAPIを提供するNode.js専用のZIPライブラリです。ファイルやフォルダーを簡単に圧縮でき、特に小規模なプロジェクトに適しています。ただし、ストリーミングや大規模データの処理には限界があります。

  • zip-local:

    zip-localは、ローカルファイルシステム内でZIPファイルを作成、解凍するためのシンプルなライブラリです。特に、ローカル環境でのファイル操作に特化しており、使いやすさが特徴です。APIが直感的で、迅速にZIP操作を行いたい開発者に適しています。

zip-a-folder のREADME

NPM

CircleCI Codacy Badge Codacy Coverage Known Vulnerabilities

zip-a-folder

Compress a folder into ZIP/TAR/TGZ/BR/7z. This library is trying to with as less dependencies as possible to other libraries. For ZIP, TAR and Brotli archives it uses the native Node.js compression (zlib). 7z uses the pure JavaScript lzma-js library for LZMA compression.

Feature overview:

  • ZIP archives (with optional ZIP64)
  • TAR archives (optionally gzipped or brotli-compressed)
  • 7z archives with LZMA compression (via lzma-js)
  • Fine-grained zlib/gzip/brotli/LZMA control
  • Globs (single or comma-separated)
  • Parallel directory scanning (statConcurrency)
  • Custom write streams
  • Compression presets (high, medium, uncompressed)

Table of Contents


Incompatible Changes

Version 2

Added support for comma-separated glob lists. This may change the behavior for cases previously interpreted as "folder only".

Version 3

Dual-module support (CJS + ESM).

Version 3.1

Added support for destPath to control the internal path layout of created archives.

Version 4

A major rewrite using:

  • Fully native ZIP writer (no dependencies)
  • Native TAR + gzip writer
  • ZIP64 support for large archives
  • Parallel statting (statConcurrency)
  • Strict internal path normalization mirroring classic zip-a-folder behavior
  • Native glob handling via tinyglobby

Version 5

  • COMPRESSION_LEVEL is now a plain const object whose values are string literals ('uncompressed', 'medium', 'high') instead of a numeric enum. The public API (COMPRESSION_LEVEL.high, etc.) is unchanged — only the underlying type changed from a TypeScript enum to a const satisfies object. See PR #70 by @schplitt.
  • Added exclude option — an array of glob patterns for files/directories to omit from the archive. See issue #65 by @Pomax.

Version 6 (current)

  • Native Brotli compression support for TAR archives using Node.js built-in zlib.brotliCompressSync(). Create .tar.br files with the new compressionType: 'brotli' option. Brotli typically provides better compression ratios than gzip, especially for text-based content.
  • New 7z archive format support via the sevenZip() function. Uses pure JavaScript LZMA compression (via lzma-js library) — no external binaries required. Provides excellent compression ratios with the industry-standard 7z format.
  • New brotliOptions for fine-grained control over brotli compression parameters.
  • New compressionLevel option (1-9) for 7z archives to control LZMA compression level.

Installation

npm install zip-a-folder

Usage

Create a ZIP file

import { zip } from 'zip-a-folder';

await zip('/path/to/folder', '/path/to/archive.zip');

Create a GZIP-compressed TAR file (.tgz)

import { tar } from 'zip-a-folder';

await tar('/path/to/folder', '/path/to/archive.tgz');

Compression Handling

Supported compression levels:

COMPRESSION_LEVEL.high          // highest compression (default)
COMPRESSION_LEVEL.medium        // balanced
COMPRESSION_LEVEL.uncompressed  // STORE for zip, no-gzip for tar

v5: COMPRESSION_LEVEL is now a const object with string values ('high', 'medium', 'uncompressed'). The compression option accepts either the constant (COMPRESSION_LEVEL.high) or the plain string ('high') directly.

Example:

import { zip, COMPRESSION_LEVEL } from 'zip-a-folder';

await zip('/path/to/folder', '/path/to/archive.zip', {
    compression: COMPRESSION_LEVEL.medium  // or just 'medium'
});

ZIP Options

OptionTypeDescription
commentstringZIP file comment
forceLocalTimebooleanUse local timestamps instead of UTC
forceZip64booleanAlways include ZIP64 headers
namePrependSlashbooleanPrefix all ZIP entry names with /
storebooleanForce STORE method (no compression)
zlibZlibOptionsPassed directly to zlib.deflateRaw
statConcurrencynumberParallel stat workers (default: 4)
destPathstringPrefix inside the archive (>=3.1)
excludestring[]Glob patterns for paths to omit
customWriteStreamWriteStreamManually handle output

Example:

await zip('/dir', '/archive.zip', {
    comment: "Created by zip-a-folder",
    forceZip64: true,
    namePrependSlash: true,
    store: false,
    statConcurrency: 16,
    zlib: { level: 9 }
});

TAR / TGZ / TAR.BR Options

OptionTypeDescription
compressionType'none' | 'gzip' | 'brotli'Compression algorithm (default: 'gzip')
gzipbooleanEnable gzip compression (deprecated, use compressionType)
gzipOptionsZlibOptionsPassed to zlib.createGzip
brotliOptionsBrotliOptionsPassed to zlib.createBrotliCompress
statConcurrencynumberParallel stat workers
excludestring[]Glob patterns to omit
compressionCOMPRESSION_LEVELConvenience preset (high, medium, uncompressed)

Gzip Example

await tar('/dir', '/archive.tgz', {
    compressionType: 'gzip',
    gzipOptions: { level: 6 }
});

Brotli Example

Brotli compression is supported natively via Node.js zlib module (available since Node.js v10.16.0). Brotli typically provides better compression ratios than gzip, especially for text-based content.

import { tar, COMPRESSION_LEVEL } from 'zip-a-folder';
import * as zlib from 'zlib';

// Simple brotli compression
await tar('/dir', '/archive.tar.br', {
    compressionType: 'brotli'
});

// With compression level preset
await tar('/dir', '/archive.tar.br', {
    compressionType: 'brotli',
    compression: COMPRESSION_LEVEL.high
});

// With custom brotli options
await tar('/dir', '/archive.tar.br', {
    compressionType: 'brotli',
    brotliOptions: {
        params: {
            [zlib.constants.BROTLI_PARAM_QUALITY]: 11,  // 0-11, higher = better compression
            [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT
        }
    }
});

Uncompressed TAR

await tar('/dir', '/archive.tar', {
    compressionType: 'none'
});

7z Options

Create 7z archives with LZMA compression using the sevenZip() function.

OptionTypeDescription
compressionCOMPRESSION_LEVELConvenience preset (high, medium, uncompressed)
compressionLevelnumber (1-9)LZMA compression level (default: 5)
statConcurrencynumberParallel stat workers (default: 4)
excludestring[]Glob patterns to omit
customWriteStreamWriteStreamManually handle output

Basic Example

import { sevenZip } from 'zip-a-folder';

await sevenZip('/path/to/folder', '/path/to/archive.7z');

With Compression Level

import { sevenZip, COMPRESSION_LEVEL } from 'zip-a-folder';

// Using preset
await sevenZip('/dir', '/archive.7z', {
    compression: COMPRESSION_LEVEL.high
});

// Using explicit level (1-9)
await sevenZip('/dir', '/archive.7z', {
    compressionLevel: 9
});

With Glob Patterns

await sevenZip('src/**/*.ts', '/archive.7z');

With Exclusions

await sevenZip('/project', '/archive.7z', {
    exclude: ['node_modules/**', '**/*.log']
});

Note: 7z archives use LZMA compression via the lzma-js library. This provides excellent compression ratios, especially for text-based content. The 7z format stores files as a solid archive, meaning all file data is concatenated and compressed together for better compression efficiency.


Custom Write Streams

ZIP and TAR can be written into any stream. If customWriteStream is used, the targetFilePath can be empty or undefined.

import fs from 'fs';
import { zip } from 'zip-a-folder';

const ws = fs.createWriteStream('/tmp/output.zip');
await zip('/path/to/folder', undefined, { customWriteStream: ws });

Important: zip-a-folder does not validate custom streams. You must ensure:

  • parent directory exists
  • you're not writing into the source directory (to avoid recursion)

Glob Handling

The first parameter may be:

  • A path to a directory
  • A single glob
  • A comma-separated list of globs

Example:

await zip('**/*.json', '/archive.zip');
await zip('**/*.json, **/*.txt', '/archive2.zip');

If no files match, zip-a-folder throws:

Error: No glob match found

Destination Path Handling (destPath)

Adds a prefix inside the archive:

await zip('data/', '/archive.zip', { destPath: 'data/' });

Resulting ZIP layout:

data/file1.txt
data/subdir/file2.txt

Directory Root Inclusion Semantics

When passing a directory path as the first argument (e.g. zip('/path/to/folder', '/archive.zip')), the archive by default contains the contents of that directory at the archive root (i.e. you will see the files inside folder/, not a top-level folder/ directory itself).

Include the directory itself

If you want the archive to unpack into the named folder (so the top level of the archive contains folder/), set destPath to that folder name plus a trailing slash:

await zip('/path/to/folder', '/archive.zip', {
  destPath: 'folder/'
});

Result layout:

folder/file1.txt
folder/sub/file2.txt

Summary

  • Default: directory contents only (no enclosing folder)
  • To include the folder: use destPath: '<dirname>/'

This applies equally to tar().


Excluding Files and Directories (exclude)

The exclude option accepts an array of picomatch-style glob patterns. Matching entries (files and directories) are omitted from the archive entirely — when a directory is excluded its entire subtree is skipped.

import { zip } from 'zip-a-folder';

const packed = await zip('/path/to/project', '/path/to/archive.zip', {
  exclude: [
    // dot-files (.env, .DS_Store, …)
    '**/.*',
    // dot-directories (.git, .vscode, …) and their contents
    '**/.*/**',
    // build output and dependencies
    'dist/**',
    'dist/',
    'node_modules/**',
    'node_modules/',
  ]
});

Notes:

  • exclude is applied to directory sources and glob sources alike.
  • For glob sources, the patterns are passed as additional ignore entries to tinyglobby.
  • Patterns are matched against relative paths inside the source directory (POSIX-style).
  • To exclude a whole directory tree, add both dirname/ and dirname/** (or just dirname/**).

Inspired by issue #65 reported by @Pomax.


Module Import Structure

Note: As of v4 and the modernized build, all code is bundled into a single entry file. Do not import submodules (e.g. dist/lib/mjs/core/types). Always import from the main entry point:

import { zip, tar, COMPRESSION_LEVEL } from 'zip-a-folder';

If you need types, import from the main entry point as well:

import type { ZipArchiveOptions, TarArchiveOptions } from 'zip-a-folder';

Native Implementation Notes

  • ZIP and TAR are written using pure Node.js (zlib, raw buffering)
  • ZIP64 support included
  • File system scanning performed with a parallel stat queue
  • Globs handled via the tinyglobby package
  • Archive layout matches the original zip-a-folder for compatibility
  • ZIP writer supports dependency-free deflate and manual header construction
  • TAR writer produces POSIX ustar format with proper 512-byte block alignment

Unix Permissions Preservation in ZIP

A recent contribution restored correct handling of file modes for Unix systems inside ZIP archives:

  • The "Version Made By" field is now set to Unix (upper byte = 3) in the Central Directory.
  • File modes from fs.stat().mode are passed through to the ZIP entries and preserved.
  • Modes are mapped into the upper 16 bits of the "External File Attributes" field per the ZIP spec.

This brings parity back with v3 behavior and ensures executables and other POSIX permissions are preserved when packaging for Linux/Debian and similar environments.

See PR #66: https://github.com/maugenst/zip-a-folder/pull/66

Automated tests were added to validate:

  • Central Directory "Version Made By" upper byte is 3 (Unix).
  • External File Attributes store the POSIX mode (both files and directories), including directory flag.
  • FileCollector behavior and glob handling are fully covered, pushing coverage to 100% lines/functions.

Command Line Interface (CLI)

zip-a-folder includes a CLI for quick archive creation from the terminal.

Installation

# Global installation
npm install -g zip-a-folder

# Or use via npx
npx zip-a-folder ./folder ./archive.zip

Usage

zip-a-folder <source> <target> [options]

Supported Formats

ExtensionDescription
.zipZIP archive (deflate compression)
.tarTAR archive (uncompressed)
.tgzTAR archive with gzip compression
.tar.gzTAR archive with gzip compression
.tar.brTAR archive with brotli compression
.7z7z archive with LZMA compression

Options

OptionDescription
-h, --helpShow help message
-V, --versionShow version number
-v, --verboseShow detailed progress (files being processed)
-q, --quietSuppress all output except errors
-c, --compression <level>Compression preset: high, medium, uncompressed
-l, --level <number>Compression level (1-9, format-specific)
-e, --exclude <pattern>Glob pattern to exclude (can be used multiple times)
-d, --dest-path <path>Destination path prefix inside archive

Examples

# Create a ZIP archive
zip-a-folder ./my-folder ./archive.zip

# Create a gzipped TAR with verbose output
zip-a-folder ./src ./backup.tgz -v

# Create a 7z archive with maximum compression
zip-a-folder ./project ./project.7z -c high

# Create archive excluding node_modules
zip-a-folder ./app ./app.zip -e "node_modules/**" -e "**/*.log"

# Create brotli-compressed TAR
zip-a-folder ./data ./data.tar.br -v

# Use glob patterns
zip-a-folder "src/**/*.ts" ./source.zip

# Quiet mode (only errors)
zip-a-folder ./folder ./archive.zip -q

Output

By default, the CLI shows a summary with:

  • Source and target paths
  • Archive format
  • File count
  • Original and compressed sizes
  • Compression ratio
  • Processing time

Use -v for detailed file-by-file progress, or -q to suppress all output.


Running Tests

Tests are written in Vitest with full coverage (100% statements/branches/functions/lines):

npm test

Coverage is reported automatically via @vitest/coverage-v8.


Thanks

Special thanks to contributors:

  • @sole – initial work
  • @YOONBYEONGIN
  • @Wunschik
  • @ratbeard
  • @Xotabu4
  • @dallenbaldwin
  • @wiralegawa
  • @karan-gaur
  • @malthe
  • @nesvet
  • @schplitt – string-literal compression levels refactor (PR #70)
  • @Pomax – exclude option feature request (issue #65)

Additional thanks to everyone helping shape the native rewrite.