Skip to content

Compression Middleware Patterns — Complete Implementation Guide

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Compression Middleware Patterns. We cover key concepts, practical examples, and best practices to help you master this topic.

Compression middleware patterns reduce response payload sizes by applying gzip or brotli compression automatically, cutting bandwidth usage and improving page load times for API consumers.

What You'll Learn

By the end of this tutorial, you will implement compression middleware that negotiates compression algorithms with clients, applies optimal compression levels, and skips compression for already-compressed data.

Why It Matters

Compression reduces bandwidth costs by up to 80% and significantly improves response times. DodaTech's APIs compress all JSON responses, cutting average response size from 50KB to 6KB.

Real-World Use

Doda Browser's bookmark sync API compresses large sync payloads with brotli compression, reducing sync times from 3 seconds to 400 milliseconds for users with thousands of bookmarks.

Compression Middleware Learning Path

flowchart LR
  A[Validation Middleware] --> B[Compression Middleware]
  B --> C[Gzip vs Brotli]
  C --> D[Performance Tuning]
  B --> E{You Are Here}
  style E fill:#f90,color:#fff

Basic Gzip Compression

The compression npm package adds gzip compression to any Express application with a single line of middleware.

const express = require("express");
const compression = require("compression");
const app = express();

app.use(compression());

app.get("/data", (req, res) => {
  const largeData = {
    users: Array(1000).fill(null).map((_, i) => ({
      id: i,
      name: `User ${i}`,
      email: `user${i}@example.com`,
      bio: "A very long bio string that repeats many times to demonstrate compression benefits and how well gzip handles repetitive text patterns in JSON payloads."
    }))
  };
  res.json(largeData);
});

app.listen(3000);

Expected behavior: The response is automatically gzip-compressed. Without compression, the payload is approximately 150KB. With compression, it drops to approximately 12KB.

Dynamic Compression Levels

Different types of content benefit from different compression levels. Higher levels compress better but use more CPU.

const express = require("express");
const compression = require("compression");
const app = express();

function dynamicCompression(req, res, next) {
  const shouldCompress = (req, res) => {
    if (req.headers["x-no-compression"]) {
      return false;
    }
    return compression.filter(req, res);
  };

  compression({
    level: 6,
    threshold: 1024,
    filter: shouldCompress,
    chunkSize: 16384
  })(req, res, next);
}

app.use(dynamicCompression);

app.get("/small", (req, res) => {
  res.json({ message: "Small payload" });
});

app.get("/large", (req, res) => {
  res.json({ data: "x".repeat(100000) });
});

app.listen(3000);

Expected behavior: The /small response is under 1024 bytes and is not compressed. The /large response exceeds the threshold and is compressed. The x-no-compression header can disable compression for specific clients.

Brotli Compression

Brotli provides better compression ratios than gzip, especially for text content. For Node.js 11.7+, the compression package supports brotli automatically if the client advertises support.

const express = require("express");
const { createBrotliCompress } = require("zlib");
const app = express();

function brotliMiddleware(req, res, next) {
  const acceptEncoding = req.headers["accept-encoding"] || "";

  if (acceptEncoding.includes("br")) {
    res.setHeader("Content-Encoding", "br");
    const compressor = createBrotliCompress({
      params: {
        [require("zlib").constants.BROTLI_PARAM_QUALITY]: 4
      }
    });
    const originalWrite = res.write.bind(res);
    const originalEnd = res.end.bind(res);

    res.write = (chunk) => compressor.write(chunk);
    res.end = (chunk) => compressor.end(chunk);

    compressor.on("data", (compressed) => originalWrite(compressed));
    compressor.on("end", () => originalEnd());
  }

  next();
}

app.use(brotliMiddleware);

app.get("/data", (req, res) => {
  res.json({ message: "Compressed with brotli if supported" });
});

app.listen(3000);

Expected behavior: When the client sends Accept-Encoding: br, the response is brotli-compressed. Otherwise, it is sent uncompressed. Brotli typically achieves 10-20% better compression than gzip.

Common Mistakes

  1. Compressing already-compressed data — Images, videos, and PDFs are already compressed. Compressing them wastes CPU and may increase size.

  2. Setting compression level too high — Level 9 saves a few more bytes but uses significantly more CPU. Level 6 balances speed and compression.

  3. Not Caching compressed responses — Compute compression once and cache the result for frequently accessed resources.

  4. Compressing small responses — Responses under 1KB may become larger after compression due to overhead. Set a threshold.

  5. Not checking Accept-Encoding -- Compressing when the client does not support it wastes CPU and may corrupt the response.

Practice Questions

  1. What is the difference between gzip and brotli compression? Brotli achieves better compression ratios (10-20% smaller) but requires more CPU. Both are supported by modern browsers.

  2. Why set a compression threshold? Small payloads may grow after adding compression headers. A threshold skips compression for trivial responses.

  3. Which content types benefit most from compression? Text content: JSON, HTML, CSS, JavaScript. Binary content like images is already compressed.

  4. Challenge: Implement compression middleware that caches compressed responses in memory.

const cache = new Map();
app.use((req, res, next) => {
  const key = req.url;
  if (cache.has(key)) {
    res.setHeader("Content-Encoding", "gzip");
    return res.send(cache.get(key));
  }
  next();
});

FAQ

Does compression affect API latency?

Compression adds CPU overhead but reduces network transfer time. For most APIs, the net effect is faster responses due to reduced bandwidth.

Should I use compression behind a reverse proxy?

Yes. Offload compression to Nginx or a CDN. This frees your application server from CPU-intensive compression work.

How do I compress server-sent events (SSE)?

SSE streams are typically not compressed because they are long-lived. Compress individual messages instead of the stream.

Can I use compression with WebSocket connections?

WebSocket frames can be compressed using the permessage-deflate extension, but standard HTTP compression middleware does not apply to WebSockets.

How do I verify compression is working?

Check the Content-Encoding response header. Values are gzip, br (brotli), or deflate. Also compare response sizes with and without compression.

Mini Project

Build a compression middleware system with dynamic algorithm selection, threshold, and exclusion rules for different content types.

const express = require("express");
const compression = require("compression");
const app = express();

app.use(compression({
  level: 6,
  threshold: 1024,
  filter: (req, res) => {
    if (req.headers["x-no-compression"]) {
      return false;
    }
    const type = res.getHeader("Content-Type");
    if (type && (type.includes("image") || type.includes("video"))) {
      return false;
    }
    return compression.filter(req, res);
  }
}));

app.get("/api/users", (req, res) => {
  const users = Array(500).fill(null).map((_, i) => ({
    id: i,
    name: `User ${i}`,
    email: `user${i}@test.com`
  }));
  res.json(users);
});

app.get("/static/logo.png", (req, res) => {
  res.setHeader("Content-Type", "image/png");
  res.send(Buffer.alloc(100000));
});

app.listen(3000);

What's Next

Now that you understand compression middleware, explore handling cross-origin requests with middleware. Then learn about implementing rate limiting as middleware.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro