On this page

C

zlib.ZipFile

History
Stability: 1.0Early development

The ZIP archive API is experimental. Using any part of it (this class among them) emits an experimental warning the first time; merely importing node:zlib does not.

A random-access view over the entries of a ZIP archive on disk. Only the archive's tail and central directory are read up front; member content is read from disk lazily, on demand. Writable when opened with { writable: true }: zipFile.addEntry()/zipFile.add() append the new member's data where the central directory used to be, then rewrite the central directory immediately after it; zipFile.delete() just rewrites the central directory. Both mean the file is altered as soon as the method's returned Promise fulfills. Deleted or replaced members are left behind as dead space; zipFile.compact() produces a stream with none.

These in-place edits are not crash-atomic. Rewriting the central directory happens in place, so a write that fails partway - the disk fills, the device disconnects, the process is killed - can leave the archive on disk with a partial or missing central directory, i.e. unreadable, even though the member data before it is intact. The rejected call surfaces the underlying error and the ZipFile object is left usable (its in-memory view is not discarded, so a caller can attempt recovery - for example re-writing the entries elsewhere with zipFile.compact()), but that in-memory view may no longer match the bytes on disk. Write to a copy, or compact() into a fresh file, when durability across a failure matters.

Every method has a *Sync counterpart. As with the synchronous node:fs APIs, these block the Node.js event loop and further JavaScript execution until the operation completes; use them only where synchronous execution is appropriate (for example, short-lived scripts or startup code), not in code that must stay responsive. A synchronous method throws ERR_INVALID_STATE if called while an asynchronous add(), addEntry(), delete(), or close() on the same ZipFile has not settled yet, since letting the two interleave could corrupt the archive.

import { ZipFile } from 'node:zlib';
import { Buffer } from 'node:buffer';

const zip = await ZipFile.open('archive.zip', { writable: true });
try {
  const entry = await zip.get('member.txt');
  console.log((await entry.content()).toString());
  for await (const chunk of await zip.stream('huge.bin')) {
    // Process each chunk without buffering the whole member.
  }
  await zip.add('new.txt', Buffer.from('hello'));
  await zip.delete('unwanted.txt');
} finally {
  await zip.close();
}
const { ZipFile } = require('node:zlib');

async function main() {
  const zip = await ZipFile.open('archive.zip', { writable: true });
  try {
    const entry = await zip.get('member.txt');
    console.log((await entry.content()).toString());
    for await (const chunk of await zip.stream('huge.bin')) {
      // Process each chunk without buffering the whole member.
    }
    await zip.add('new.txt', Buffer.from('hello'));
    await zip.delete('unwanted.txt');
  } finally {
    await zip.close();
  }
}
main();
S

zlib.ZipFile.open

History
zlib.ZipFile.open(filename, options?): Promise
Attributes
filename:string
options:Object
writable?:boolean
Open the underlying file for both reading and writing ('r+'), enabling zipFile.addEntry()/zipFile.add()/ zipFile.delete(). Default: false.
Returns:Promise
Fulfilled with a ZipFile.

Throws an ERR_ZIP_ARCHIVE_TOO_LARGE error if the archive's central directory is too large to buffer in memory.

S

zlib.ZipFile.openSync

History
zlib.ZipFile.openSync(filename, options?): ZipFile
Attributes
filename:string
Returns:ZipFile

The synchronous version of zlib.ZipFile.open().

M

zipFile.add

History
zipFile.add(filename, data, options?): Promise
Attributes
filename:string
The entry's name within the archive. A trailing / marks a directory entry.
The entry's complete, uncompressed content.
Returns:Promise
Fulfilled with the created ZipEntry.

Equivalent to zipFile.addEntry(await zlib.ZipEntry.create(filename, data, options)).

M

zipFile.addEntry

History
zipFile.addEntry(entry): Promise
Attributes
entry:ZipEntry
Returns:Promise
Fulfilled with entry.

Writes entry where the central directory currently starts, then rewrites the central directory to include it, replacing any existing entry of the same name. Throws ERR_ZIP_NOT_WRITABLE if the ZipFile was not opened with { writable: true }.

The returned (same) entry is left readable: a streaming entry created with zlib.ZipEntry.createStream(), which would otherwise be spent once serialized, is promoted in place to a file-backed entry pointing at the copy just written (valid while this ZipFile is open). In-memory entries keep their own buffer unchanged.

M

zipFile.addEntrySync

History
zipFile.addEntrySync(entry): ZipEntry
Attributes
entry:ZipEntry
Returns:ZipEntry
entry.

The synchronous version of zipFile.addEntry(). entry must not be a pending streaming entry (one created with zlib.ZipEntry.createStream()) - there is no synchronous way to drain its asynchronous source.

M

zipFile.addSync

History
zipFile.addSync(filename, data, options?): ZipEntry
Attributes
filename:string
The entry's name within the archive. A trailing / marks a directory entry.
The entry's complete, uncompressed content.
Returns:ZipEntry
The created entry.

The synchronous version of zipFile.add(). Equivalent to zipFile.addEntrySync(zlib.ZipEntry.createSync(filename, data, options)).

M

zipFile.close

History
zipFile.close(): Promise
Returns:Promise

Closes the underlying file handle.

Closing does not invalidate outstanding objects: ZipEntry objects previously returned by zipFile.get() and the ZipFile's own methods will fail with system-level errors (for example EBADF) if used after close, rather than a dedicated Node.js error code. The same applies to zipFile.closeSync().

M

zipFile.closeSync

History
zipFile.closeSync(): void

The synchronous version of zipFile.close().

P

zipFile.comment

History
Type:string

The archive-level comment, preserved byte-for-byte across zipFile.addEntry()/zipFile.delete() calls. The bytes are decoded as UTF-8 when they are valid UTF-8 and as CP437 otherwise (the field carries no encoding flag of its own).

M

zipFile.compact

History
zipFile.compact(comment?): stream.Readable
Attributes
comment?:string
An archive comment. Default: zipFile.comment.
A stream of the currently live entries, serialized as a fresh archive with no dead space left by prior zipFile.addEntry()/zipFile.delete() calls.

Does not modify the open file; pipe the result into a new one:

import { createWriteStream } from 'node:fs';
zip.compact().pipe(createWriteStream('compacted.zip'));
M

zipFile.compactSync

History
zipFile.compactSync(comment?): Buffer
Attributes
comment?:string
An archive comment. Default: zipFile.comment.
Returns:Buffer
The currently live entries, serialized as a fresh archive with no dead space left by prior zipFile.addEntry()/zipFile.delete() calls.

The synchronous version of zipFile.compact(). Does not modify the open file.

M

zipFile.delete

History
zipFile.delete(name): Promise
Attributes
name:string
Returns:Promise
Fulfilled with true if an entry named name existed and was removed, false otherwise.

Rewrites the central directory without writing any new content - the archive does not grow. Throws ERR_ZIP_NOT_WRITABLE if the ZipFile was not opened with { writable: true }.

M

zipFile.deleteSync

History
zipFile.deleteSync(name): boolean
Attributes
name:string
Returns:boolean
true if an entry named name existed and was removed, false otherwise.

The synchronous version of zipFile.delete().

M

zipFile.entries

History
zipFile.entries(): Iterator
Returns:Iterator
of [name, entry] pairs, where entry is a Promise fulfilled with a ZipEntry.
M

zipFile.entriesSync

History
zipFile.entriesSync(): Iterator
Returns:Iterator
of [name, entry] pairs, where entry is a resolved ZipEntry (not a Promise).

The synchronous version of zipFile.entries().

M

zipFile.forEach

History
zipFile.forEach(callback, thisArg?): void
Attributes
callback:Function
thisArg:any
M

zipFile.forEachSync

History
zipFile.forEachSync(callback, thisArg?): void
Attributes
callback:Function
thisArg:any

The synchronous version of zipFile.forEach(): callback is invoked with a resolved ZipEntry instead of a Promise.

M

zipFile.get

History
zipFile.get(name): Promise
Attributes
name:string
Returns:Promise
Fulfilled with a ZipEntry.

Returns a lazy, file-backed ZipEntry for name. Nothing is read from disk here and no content is buffered: the returned entry reads (and, for zipEntry.content(), decompresses) its member straight from the file on each access, and the ZipFile retains no member content. The entry is valid only while this ZipFile is open. Reading its content later may throw ERR_ZIP_ENTRY_TOO_LARGE if the member is too large to hold in a single buffer; use zipEntry.contentIterator() (or zipFile.stream()) instead. Throws ERR_ZIP_ENTRY_NOT_FOUND if the archive has no entry named name.

M

zipFile.getSync

History
zipFile.getSync(name): ZipEntry
Attributes
name:string
Returns:ZipEntry

The synchronous version of zipFile.get(). Like get(), it reads nothing up front and only builds the lazy handle, so it does not itself block on I/O - but reads performed later through the returned entry (such as zipEntry.contentSync()) do; see the note above on synchronous methods.

M

zipFile.has

History
zipFile.has(name): boolean
Attributes
name:string
Returns:boolean
M

zipFile.keys

History
zipFile.keys(): Iterator
Returns:Iterator
of entry names.
P

zipFile.size

History
Type:number

The number of entries in the archive.

M

zipFile.stream

History
zipFile.stream(name, options?): Promise
Attributes
name:string
options:Object
verify?:boolean
Verify the entry's CRC-32 checksum. Default: true.
maxSize?:number
Reject content declaring more than this many uncompressed bytes. Default: no limit.
Returns:Promise
Fulfilled with a stream.Readable of the member's decompressed content, without buffering the whole member in memory.

Convenience wrapper that resolves to a Readable over zipEntry.contentIterator() of zipFile.get()(name); the compressed bytes are read from disk as the stream is consumed. The returned promise rejects with ERR_ZIP_ENTRY_NOT_FOUND if the archive has no entry named name.

M

zipFile.values

History
zipFile.values(): Iterator
Returns:Iterator
of Promise objects, each fulfilled with a ZipEntry.
M

zipFile.valuesSync

History
zipFile.valuesSync(): Iterator
Returns:Iterator
of resolved ZipEntry values (not Promises).

The synchronous version of zipFile.values().

P

zipFile.writable

History
Type:boolean

Whether this ZipFile was opened with { writable: true }.