Zip/Tar a complete folder or a glob list into a zip/tgz file
npm install zip-a-folder




- ZIP archives (with optional ZIP64)
- TAR archives (optionally gzipped)
- Globs (single or comma-separated)
- Parallel directory scanning (statConcurrency)
- Custom write streams
- Compression presets (high, medium, uncompressed)
- Fine-grained zlib/gzip control
Everything is implemented natively without JS zip/tar libraries.
---
destPath to control the internal path layout of created archives.statConcurrency)glob---
``bash``
npm install zip-a-folder
---
`js
import { zip } from 'zip-a-folder';
await zip('/path/to/folder', '/path/to/archive.zip');
`
)`js
import { tar } from 'zip-a-folder';
await tar('/path/to/folder', '/path/to/archive.tgz');
`
---
Supported compression levels:
`ts`
COMPRESSION_LEVEL.high // highest compression (default)
COMPRESSION_LEVEL.medium // balanced
COMPRESSION_LEVEL.uncompressed // STORE for zip, no-gzip for tar
Example:
`js
import { zip, COMPRESSION_LEVEL } from 'zip-a-folder';
await zip('/path/to/folder', '/path/to/archive.zip', {
compression: COMPRESSION_LEVEL.medium
});
`
---
| Option | Type | Description |
| ------------------- | ------------- | ------------------------------------ |
| comment | string | ZIP file comment |forceLocalTime
| | boolean | Use local timestamps instead of UTC |forceZip64
| | boolean | Always include ZIP64 headers |namePrependSlash
| | boolean | Prefix all ZIP entry names with / |store
| | boolean | Force STORE method (no compression) |zlib
| | ZlibOptions | Passed directly to zlib.deflateRaw |statConcurrency
| | number | Parallel stat workers (default: 4) |destPath
| | string | Prefix inside the archive (>=3.1) |customWriteStream
| | WriteStream | Manually handle output |
Example:
`js`
await zip('/dir', '/archive.zip', {
comment: "Created by zip-a-folder",
forceZip64: true,
namePrependSlash: true,
store: false,
statConcurrency: 16,
zlib: { level: 9 }
});
---
| Option | Type | Description |
| ----------------- | ------------- | --------------------------- |
| gzip | boolean | Enable gzip compression |gzipOptions
| | ZlibOptions | Passed to zlib.createGzip |statConcurrency
| | number | Parallel stat workers |
Example:
`js`
await tar('/dir', '/archive.tgz', {
gzip: true,
gzipOptions: { level: 6 }
});
---
ZIP and TAR can be written into any stream.
If customWriteStream is used, the targetFilePath can be empty or undefined.
`js
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)
---
The first parameter may be:
* A path to a directory
* A single glob
* A comma-separated list of globs
Example:
`js`
await zip('*/.json', '/archive.zip');
await zip('/.json, /.txt', '/archive2.zip');
If no files match, zip-a-folder throws:
``
Error: No glob match found
---
)Adds a prefix inside the archive:
`js`
await zip('data/', '/archive.zip', { destPath: 'data/' });
Resulting ZIP layout:
``
data/file1.txt
data/subdir/file2.txt
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).
), set destPath to that folder name plus a trailing slash:`ts
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: 'This applies equally to
tar().---
🎯 Native Implementation Notes (New in v4)
* 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 standardized glob 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---
🧪 Running Tests
Tests are written in Jest:
`bash
npm test
`A coverage report is included:
`bash
npm test -- --coverage
``---
Special thanks to contributors:
* @sole – initial work
* @YOONBYEONGIN
* @Wunschik
* @ratbeard
* @Xotabu4
* @dallenbaldwin
* @wiralegawa
* @karan-gaur
* @malthe
Additional thanks to everyone helping shape the native rewrite.