Skip to main content
Response compression reduces the size of your API responses, improving performance and reducing bandwidth costs. Express Zod API supports GZIP and Brotli compression through the compression package.

Installation

First, install the required packages:
npm install compression @types/compression
# or
pnpm add compression @types/compression
# or
yarn add compression @types/compression

Enabling Compression

Enable compression in your configuration:
import { createConfig } from "express-zod-api";

const config = createConfig({
  http: { listen: 8090 },
  compression: true, // Enable with default settings
});
That’s it! Your API responses will now be compressed automatically.

Configuration Options

For more control, pass configuration options:
import { createConfig } from "express-zod-api";

const config = createConfig({
  http: { listen: 8090 },
  compression: {
    threshold: "1kb", // Only compress responses larger than 1KB
    level: 6, // Compression level (0-9, default: 6)
  },
});

Available Options

OptionTypeDefaultDescription
thresholdstring | number1024Minimum response size to compress (bytes or string like “1kb”)
levelnumber6Compression level (0=none, 9=max, -1=default)
strategynumber-Compression strategy for GZIP
chunkSizenumber16384Chunk size for compression
memLevelnumber8Memory level for GZIP (1-9)

How It Works

When a client sends a request with the Accept-Encoding header, the server responds with compressed data:
curl -H "Accept-Encoding: br, gzip, deflate" \
  https://api.example.com/v1/users
The client automatically decompresses the response.

Compression Algorithms

Express Zod API supports multiple compression algorithms:
  1. Brotli (br) - Best compression, slower
  2. GZIP (gzip) - Good compression, fast
  3. Deflate (deflate) - Older, less efficient
The server automatically chooses the best algorithm based on the client’s Accept-Encoding header.

What Gets Compressed?

Only responses with compressible content types are compressed:
  • application/json
  • text/html
  • text/plain
  • text/css
  • application/javascript
  • image/jpeg ❌ (already compressed)
  • image/png ❌ (already compressed)
  • video/* ❌ (already compressed)

Minimum Size Threshold

Small responses aren’t worth compressing due to overhead. Set a threshold:
const config = createConfig({
  compression: {
    threshold: "1kb", // Don't compress responses smaller than 1KB
  },
});
Common threshold values:
  • 1kb (1024 bytes) - Default, good for most APIs
  • 512 (512 bytes) - More aggressive
  • 2kb (2048 bytes) - Less aggressive

Compression Levels

Balance compression ratio vs. CPU usage:
const config = createConfig({
  compression: {
    level: 6, // Default
    // level: 1, // Fastest, less compression
    // level: 9, // Slowest, max compression
  },
});
LevelSpeedCompressionUse Case
1FastestMinimalHigh-traffic APIs, CPU-constrained
6BalancedGoodDefault, most use cases
9SlowestMaximumLow-traffic, bandwidth-constrained

Real-World Example

From the Express Zod API example:
import { createConfig } from "express-zod-api";

const config = createConfig({
  http: { listen: 8090 },
  compression: true, // Affects image streaming endpoint
  upload: {
    limits: { fileSize: 51200 },
  },
});

Testing Compression

Verify compression is working:
# Test with curl
curl -H "Accept-Encoding: gzip" \
  -v \
  https://api.example.com/v1/users

# Look for:
# < Content-Encoding: gzip
Or use browser DevTools:
  1. Open Network tab
  2. Make request to your API
  3. Check response headers for Content-Encoding: gzip or Content-Encoding: br
  4. Compare “Size” vs “Transferred” columns

Performance Impact

Benefits

  • Reduced bandwidth: 60-80% smaller responses for JSON
  • Faster transfer: Especially on slow connections
  • Lower costs: Reduced data transfer fees

Trade-offs

  • CPU usage: Compression takes processing time
  • Latency: Minimal increase for compression/decompression
  • Memory: Buffering during compression

Benchmarks

Typical JSON response (10KB uncompressed):
AlgorithmSizeRatioCompression Time
None10KB--
GZIP (level 6)2.5KB75%~1ms
Brotli2.0KB80%~2ms

When NOT to Use Compression

Already Compressed Content

Images, videos, and PDFs are already compressed. Don’t compress them again.

Very Small Responses

Responses under 150 bytes may become larger when compressed due to overhead.

CPU-Constrained Servers

If CPU is your bottleneck, compression may hurt more than help.

Streaming Responses

Streaming with compression is complex. Consider pre-compression instead.

Advanced Configuration

Environment-Based

const config = createConfig({
  compression: process.env.NODE_ENV === "production" ? {
    threshold: "1kb",
    level: 6,
  } : false, // Disable in development
});

Custom Filter

While Express Zod API doesn’t expose the filter directly, you can use beforeRouting:
import compression from "compression";

const config = createConfig({
  compression: false, // Disable built-in
  beforeRouting: ({ app }) => {
    app.use(
      compression({
        filter: (req, res) => {
          // Custom logic
          if (req.headers["x-no-compression"]) {
            return false;
          }
          return compression.filter(req, res);
        },
      })
    );
  },
});

Monitoring Compression

Add logging to track compression effectiveness:
const config = createConfig({
  compression: { threshold: "1kb" },
  beforeRouting: ({ app, getLogger }) => {
    const logger = getLogger();
    
    app.use((req, res, next) => {
      const originalWrite = res.write;
      const originalEnd = res.end;
      let uncompressedSize = 0;
      
      res.write = function (chunk: any, ...args: any[]) {
        if (chunk) uncompressedSize += chunk.length;
        return originalWrite.apply(res, [chunk, ...args]);
      };
      
      res.end = function (chunk: any, ...args: any[]) {
        if (chunk) uncompressedSize += chunk.length;
        
        const compressed = res.getHeader("content-encoding");
        if (compressed && uncompressedSize > 0) {
          logger.debug("Compressed response", {
            path: req.path,
            uncompressedSize,
            encoding: compressed,
          });
        }
        
        return originalEnd.apply(res, [chunk, ...args]);
      };
      
      next();
    });
  },
});

Best Practices

Always Enable in Production

Compression is a free performance win for most APIs. Enable it.

Use Default Settings

The defaults (level 6, threshold 1KB) work well for most cases.

Test with Real Data

Benchmark with your actual API responses to find optimal settings.

Monitor CPU Usage

If CPU spikes after enabling compression, reduce the level or increase threshold.

Common Issues

Compression Not Working

Check:
  1. Client sends Accept-Encoding: gzip, deflate, br
  2. Response is compressible (JSON, text)
  3. Response size exceeds threshold
  4. No other middleware interferes

Performance Degradation

If compression slows your API:
  1. Lower compression level (6 → 3)
  2. Increase threshold (1KB → 5KB)
  3. Profile to find bottleneck

Next Steps