Efficient Data Compression and Decompression in Node.js Using Zlib

Node.js includes the built-in zlib module, offering robust support for lossless data compression and decompression using industry-standard algorithms.

Compressing and Decompressing In-Memory Buffers

The zlib module provides asynchronuos utility functions for compressing and decompressing Buffer or string inputs. Each function accepts a payload and a callback that receives an error (if any) and the resulting compressed or decompressed buffer.

  • zlib.deflate() / zlib.inflate(): Implements RFC 1951 DEFLATE with zlib wrapper headers.
  • zlib.deflateRaw() / zlib.inflateRaw(): DEFLATE without header/trailer—ideal for interoperability with raw streams or custom framing.
  • zlib.gzip() / zlib.gunzip(): RFC 1952 GZIP format, including metadata like timestamps and filenmae.
  • zlib.unzip(): Generic decompressor that auto-detects and handles both GZIP and DEFLATE formats.

Below is a refactored implementation demonstrating concurrent compresion workflows with improved error handling and output clarity:

const zlib = require('zlib');
const inputText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';

// Compress with DEFLATE
zlib.deflate(inputText, (err, compressed) => {
  if (err) throw err;
  console.log(`DEFLATE size: ${compressed.length} bytes → ${compressed.toString('base64').substring(0, 24)}...`);

  zlib.inflate(compressed, (err, decompressed) => {
    if (err) throw err;
    console.assert(decompressed.toString() === inputText, 'DEFLATE round-trip failed');
  });

  zlib.unzip(compressed, (err, extracted) => {
    if (err) throw err;
    console.log(`UNZIP (DEFLATE): ${extracted.toString().length} chars`);
  });
});

// Raw DEFLATE (no wrapper)
zlib.deflateRaw(inputText, (err, rawCompressed) => {
  if (err) throw err;
  console.log(`DEFLATE-RAW size: ${rawCompressed.length} bytes`);

  zlib.inflateRaw(rawCompressed, (err, restored) => {
    if (err) throw err;
    console.assert(restored.toString() === inputText, 'DEFLATE-RAW round-trip failed');
  });
});

// GZIP workflow
zlib.gzip(inputText, (err, gzipped) => {
  if (err) throw err;
  console.log(`GZIP size: ${gzipped.length} bytes → ${gzipped.toString('base64').substring(0, 24)}...`);

  zlib.gunzip(gzipped, (err, ungziped) => {
    if (err) throw err;
    console.assert(ungziped.toString() === inputText, 'GZIP round-trip failed');
  });

  zlib.unzip(gzipped, (err, genericUnzipped) => {
    if (err) throw err;
    console.log(`UNZIP (GZIP): ${genericUnzipped.toString().length} chars`);
  });
});

Streaming File Compression and Decompression

For large files, streaming via pipe() avoids memory bloat. Transform streams like zlib.createGzip() and zlib.createGunzip() can be chained directly between readable and writable file streams.

Here's a modernized version using fs.promises and explicit stream cleanup (no setTimeout):

const fs = require('fs').promises;
const zlib = require('zlib');

async function compressFile(sourcePath, targetPath) {
  const readStream = fs.createReadStream(sourcePath);
  const gzipTransform = zlib.createGzip();
  const writeStream = fs.createWriteStream(targetPath);

  return new Promise((resolve, reject) => {
    readStream
      .pipe(gzipTransform)
      .pipe(writeStream)
      .on('finish', resolve)
      .on('error', reject);
  });
}

async function decompressFile(sourcePath, targetPath) {
  const readStream = fs.createReadStream(sourcePath);
  const gunzipTransform = zlib.createGunzip();
  const writeStream = fs.createWriteStream(targetPath);

  return new Promise((resolve, reject) => {
    readStream
      .pipe(gunzipTransform)
      .pipe(writeStream)
      .on('finish', resolve)
      .on('error', reject);
  });
}

// Usage
(async () => {
  try {
    await compressFile('input.txt', 'input.txt.gz');
    console.log('Compression completed.');

    await decompressFile('input.txt.gz', 'output.txt');
    console.log('Decompression completed.');
  } catch (e) {
    console.error('Stream operation failed:', e.message);
  }
})();

This approach ensures predictable resource management, eliminates race conditions from arbitrary timeouts, and leverages native promise-based flow control.

Tags: nodejs zlib compression streaming deflate

Posted on Thu, 23 Jul 2026 16:54:02 +0000 by saltwater