zlib.createGzip()

Creates a Transform stream that compresses data written to it into gzip format.

Signature
zlib.createGzip([options])
  • Added in Node.js v0.5.8

Parameters

ParameterTypeDescription
$optionsoptionalObjectzlib options: `level`, `strategy`, `memLevel`, `windowBits`, `chunkSize`, `flush`, `finishFlush`, `dictionary` and `maxOutputLength`, plus any Transform stream option.

Return value

zlib.GzipA new `zlib.Gzip` object — a Transform stream whose readable side emits gzip-compressed data.

Errors

Emits an `'error'` event rather than throwing; the constructor itself throws `ERR_INVALID_ARG_TYPE` or a range error for invalid options.

Changelog

  • PHP v14.5.0, v12.19.0The `maxOutputLength` option is supported.
  • PHP v5.11.0The `finishFlush` option is supported.

zlib.createGzip() returns a Transform stream: write uncompressed bytes to one side, read gzip data off the other. Nothing is buffered in full, so memory stays proportional to the chunk size rather than the payload — a 10 GB file compresses in a few hundred kilobytes of RAM.

When to reach for it

Use the stream whenever the data is large, arrives over time, or comes from a source that is already a stream: a file on disk, an HTTP response body, a database cursor, a tar pipeline. Use gzipSync() only for small buffers already in memory.

Always use pipeline, not pipe

src.pipe(gzip).pipe(dest) does not propagate errors and leaks file descriptors when something fails midway. stream.pipeline() — or the promise form from node:stream/promises — destroys every stream in the chain on failure and gives you one error to handle. This is the single most common bug in gzip stream code.

What trips people up

  • The output is not complete until the stream ends. Reading bytesWritten or concatenating chunks before 'finish' gives you a truncated archive.
  • flush() emits a sync point so a receiver can decode what has arrived so far, at the cost of compression ratio. Do not call it per chunk.
  • Piping an already-compressed source — a JPEG, an MP4 — through gzip burns CPU and grows the output.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Compress a multi-gigabyte log file to .gz without loading it into memory
  • Gzip an HTTP response body on the fly for clients that accept it
  • Add compression to a tar or backup pipeline between two streams
  • Compress records emitted by a database cursor as they arrive

Frequently asked questions

How do I gzip a file in Node.js without loading it into memory?

Pipe fs.createReadStream(src) through zlib.createGzip() into fs.createWriteStream(dest) using stream.pipeline, which keeps memory flat no matter how large the file is. Use the promise form from node:stream/promises to await it.

Should I use pipe or pipeline with createGzip?

Use pipeline — pipe does not propagate errors, so a mid-stream failure leaves dangling file descriptors and a truncated output file with no error raised. pipeline destroys every stream in the chain and reports a single error.

What is the difference between createGzip and gzipSync?

createGzip is a Transform stream that compresses incrementally with constant memory, while gzipSync compresses an entire in-memory buffer in one blocking call. Use the stream for files and network bodies, the sync call for small buffers.

More examples

Compress a file on disk with error handling

Memory stays flat regardless of file size because only one chunk is in flight at a time. pipeline destroys the read and write streams if either end fails, and the catch block removes the partial output so a failed run cannot leave a corrupt .gz that looks valid to a later reader.

Example · javascript
import zlib from 'node:zlib';
import fs from 'node:fs';
import { pipeline } from 'node:stream/promises';

async function gzipFile(from, to) {
  await pipeline(
    fs.createReadStream(from),
    zlib.createGzip({ level: 6 }),
    fs.createWriteStream(to)
  );
  const before = fs.statSync(from).size;
  const after = fs.statSync(to).size;
  console.log(`${from}: ${before} -> ${after} (${((1 - after / before) * 100).toFixed(1)}% saved)`);
}

try {
  await gzipFile('server.log', 'server.log.gz');
} catch (err) {
  console.error('compression failed:', err.message);
  fs.rmSync('server.log.gz', { force: true }); // no half-written archive
}

Gzip an HTTP response when the client accepts it

Three details matter here. Compression only happens when Accept-Encoding advertises gzip; the Vary header stops a cache from serving compressed bytes to a client that cannot decode them; and Content-Length is never set, because the compressed length is unknown until the stream ends. Level 1 keeps per-request CPU low.

Example · javascript
const http = require('node:http');
const zlib = require('node:zlib');
const { Readable, pipeline } = require('node:stream');

http.createServer((req, res) => {
  const body = Readable.from([JSON.stringify({ items: Array(500).fill('row') })]);
  const accepts = req.headers['accept-encoding'] || '';

  res.setHeader('Content-Type', 'application/json');

  if (/\bgzip\b/.test(accepts)) {
    res.setHeader('Content-Encoding', 'gzip');
    res.setHeader('Vary', 'Accept-Encoding');
    // level 1: cheap enough to run per request
    pipeline(body, zlib.createGzip({ level: 1 }), res, (err) => {
      if (err) res.destroy();
    });
  } else {
    pipeline(body, res, (err) => { if (err) res.destroy(); });
  }
}).listen(3000);

Rotate a log by streaming it into a timestamped archive

bytesWritten reports the uncompressed byte count fed into the stream, and is only final once pipeline resolves. Truncating the source strictly after the await is what makes this safe: if compression throws, pipeline rejects, the truncate never runs, and no log lines are lost.

Example · javascript
import zlib from 'node:zlib';
import fs from 'node:fs';
import { pipeline } from 'node:stream/promises';

async function rotate(logPath) {
  const stamp = new Date().toISOString().replace(/[:.]/g, '-');
  const archive = `${logPath}.${stamp}.gz`;

  const gzip = zlib.createGzip({ level: 9 });
  await pipeline(fs.createReadStream(logPath), gzip, fs.createWriteStream(archive));

  fs.truncateSync(logPath, 0); // only after the archive is durable
  console.log(`archived ${gzip.bytesWritten} bytes into ${archive}`);
}

await rotate('app.log');

Discussion

  • Be the first to comment on this lesson.