typescriptintermediate

Compression with zlib

Compress and decompress data using gzip, deflate, and brotli with Node.js built-in zlib module.

typescript
import { gzip, gunzip, deflate, inflate, brotliCompress, brotliDecompress } from 'zlib';
import { promisify } from 'util';
import { pipeline } from 'stream/promises';
import { createGzip, createGunzip, createBrotliCompress } from 'zlib';
import { createReadStream, createWriteStream } from 'fs';
import { writeFile, readFile, stat } from 'fs/promises';

const gzipAsync = promisify(gzip);
const gunzipAsync = promisify(gunzip);
const deflateAsync = promisify(deflate);
const inflateAsync = promisify(inflate);
const brotliAsync = promisify(brotliCompress);
const brotliDecompressAsync = promisify(brotliDecompress);

// Compress/decompress buffers
async function compressBuffer(data: string) {
  const input = Buffer.from(data);
  console.log(`Original: ${input.length} bytes`);

  // Gzip
  const gzipped = await gzipAsync(input);
  console.log(`Gzip: ${gzipped.length} bytes (${ratio(input.length, gzipped.length)})`);
  const ungzipped = await gunzipAsync(gzipped);
  console.log(`Verified: ${ungzipped.toString() === data}`);

  // Deflate
  const deflated = await deflateAsync(input);
  console.log(`Deflate: ${deflated.length} bytes (${ratio(input.length, deflated.length)})`);

  // Brotli
  const brotli = await brotliAsync(input);
  console.log(`Brotli: ${brotli.length} bytes (${ratio(input.length, brotli.length)})`);
}

function ratio(original: number, compressed: number): string {
  return `${((1 - compressed / original) * 100).toFixed(1)}% smaller`;
}

// Stream compression (for large files)
async function compressFile(input: string, output: string) {
  await pipeline(
    createReadStream(input),
    createGzip({ level: 9 }), // max compression
    createWriteStream(output)
  );

  const [origStat, compStat] = await Promise.all([
    stat(input),
    stat(output),
  ]);
  console.log(`\nFile compressed: ${origStat.size} → ${compStat.size} bytes`);
}

// Decompress file
async function decompressFile(input: string, output: string) {
  await pipeline(
    createReadStream(input),
    createGunzip(),
    createWriteStream(output)
  );
  console.log(`Decompressed: ${input} → ${output}`);
}

// Compress JSON for storage/transmission
async function compressJSON<T>(data: T): Promise<Buffer> {
  const json = JSON.stringify(data);
  return gzipAsync(Buffer.from(json));
}

async function decompressJSON<T>(compressed: Buffer): Promise<T> {
  const buf = await gunzipAsync(compressed);
  return JSON.parse(buf.toString());
}

// Demo
const sampleData = 'Hello '.repeat(1000);
await compressBuffer(sampleData);

const obj = { users: Array.from({ length: 100 }, (_, i) => ({ id: i, name: `User ${i}` })) };
const compressed = await compressJSON(obj);
const restored = await decompressJSON(compressed);
console.log(`\nJSON: ${JSON.stringify(obj).length} → ${compressed.length} bytes`);
console.log(`Restored ${(restored as any).users.length} users`);

Use Cases

  • API response compression
  • File compression for storage
  • Data transfer optimization

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.