DEV Community

Sasi Kumar T
Sasi Kumar T

Posted on

Tracing the Express Middleware Nobody Talks About: Compression

When we talk about observability in Node.js, we usually trace things like:

  • HTTP requests
  • Database queries
  • External API calls

But there’s a hidden performance layer most tracing setups completely ignore.

πŸ‘‰ Response compression

Many Express applications use the popular compression middleware to reduce response size and improve latency.

But here’s the problem.
Nobody traces it.


Why Compression Deserves Tracing

Compression happens after your application logic finishes but before the response is sent to the client.

That means:

HTTP Request
     β”‚
     β–Ό
Express Route
     β”‚
     β–Ό
Application Logic
     β”‚
     β–Ό
Compression (zlib)
     β”‚
     β–Ό
Response Sent
Enter fullscreen mode Exit fullscreen mode

If compression is slow, you may see:

  • slower response times
  • increased CPU usage
  • delayed response delivery

But in most observability setups, this time is invisible.

Your traces might show something like this:

HTTP Request
  └── Route Handler
        └── DB Query
Enter fullscreen mode Exit fullscreen mode

But you never see compression time.

That’s exactly the gap I wanted to close.


Introducing Compression Instrumentation

I built a small OpenTelemetry instrumentation package to trace compression operations.

πŸ‘‰ https://www.npmjs.com/package/@sasikumart/compression-instrumentation

This package instruments Node.js zlib compression calls and exposes them as OpenTelemetry spans.

It allows you to observe:

  • compression duration
  • compression algorithm used
  • impact of compression on request latency

What the Trace Looks Like

Without compression instrumentation:

HTTP GET /users
  └── controller.getUsers
        └── mongodb query
Enter fullscreen mode Exit fullscreen mode

With instrumentation:

HTTP GET /users
  └── controller.getUsers
        └── mongodb query
  └── gzip compression
Enter fullscreen mode Exit fullscreen mode

Now compression becomes a first-class span in your trace.


Installing the Instrumentation

npm install @sasikumart/compression-instrumentation
Enter fullscreen mode Exit fullscreen mode

Basic Setup

Register the instrumentation with OpenTelemetry.

import { NodeSDK } from '@opentelemetry/sdk-node';
import { ZlibInstrumentation } from '@sasikumart/compression-instrumentation';

const sdk = new NodeSDK({
  instrumentations: [
    new ZlibInstrumentation()
  ]
});

sdk.start();
Enter fullscreen mode Exit fullscreen mode

Once enabled, any gzip compression performed via Node.js zlib will automatically generate spans.


Example Express Application

Now let’s use Express with the compression middleware.

import express from "express";
import compression from "compression";

const app = express();

app.use(compression());

app.get("/data", (req, res) => {
  const payload = Array(1000).fill("OpenTelemetry is awesome");
  res.json(payload);
});

app.listen(3000, () => {
  console.log("Server running on port 3000");
});
Enter fullscreen mode Exit fullscreen mode

When a request is served, compression will trigger a zlib gzip operation, which will now appear in your traces.


Jaeger Trace Example

Here’s an example trace captured in Jaeger where the gzip compression span appears alongside the HTTP request span.

Compression Span in Jaeger

The trace typically shows:

  • HTTP request span
  • route handler span
  • gzip compression span generated by the instrumentation

What Gets Captured

Each compression operation becomes its own span, allowing you to observe:

  • how long compression takes
  • how much latency compression adds to the request
  • whether compression becomes a CPU bottleneck

Current Limitation

At the moment, the instrumentation only captures gzip compression.

This is because most Express applications using the compression middleware default to gzip via Node's zlib module.

Future versions may add support for additional algorithms such as:

  • deflate
  • brotli

Why This Matters

Compression is one of those performance optimizations everyone enables but rarely measures.

Observability should show everything that affects latency, including middleware and runtime operations.

Tracing compression helps you:

  • identify CPU bottlenecks
  • understand hidden latency in responses
  • gain deeper insight into the full request lifecycle

Real Use Cases

  • High traffic APIs: Compression CPU overhead can become significant under heavy load.
  • Large JSON responses: You can verify whether compression is actually helping reduce payload sizes.
  • Performance tuning: You can determine whether compression should happen at the application layer or a reverse proxy.

Final Thoughts

Observability often focuses on business logic, but real latency comes from every layer of the request lifecycle.

Compression is one of those layers that has remained invisible for too long.

Now it doesn’t have to be.


If you're interested in Node.js observability and OpenTelemetry, you might also like my previous deep dive:

πŸ‘‰ https://dev.to/sasikumart/tracing-the-part-of-mongoose-nobody-talks-about-3gj2


About Me

I’m a backend developer with extensive experience in designing and optimizing scalable backend systems. My expertise includes tackling complex performance challenges. I’ve led numerous database performance initiatives and have also been deeply involved in system design and revamping existing systems. My focus is on enhancing efficiency, ensuring reliability, and delivering robust solutions that scale effectively.

Feel free to connect with me on LinkedIn to learn more about my professional journey and projects.

Top comments (0)