Front-end Engineering Lab

Compression Strategies

Compress assets with Gzip, Brotli, and other techniques

Compression Strategies

Compression reduces file sizes by 70-90%, dramatically improving load times. Modern servers support multiple compression algorithms.

Compression Algorithms

Gzip (Universal Support)

Compression: 70-80% reduction
Speed: Fast
Support: 100% browsers

# Compression levels: 1 (fast) to 9 (best)
gzip -k -9 bundle.js  # Creates bundle.js.gz

Brotli (Modern, Best)

Compression: 15-20% better than Gzip
Speed: Slower compression, same decompression
Support: 95%+ browsers

# Compression levels: 0 (fast) to 11 (best)
brotli -k -q 11 bundle.js  # Creates bundle.js.br

Comparison

Original:     1000 KB
Gzip (9):      250 KB (75% reduction)
Brotli (11):   200 KB (80% reduction)

Build time:
Gzip (9):      Fast
Brotli (11):   Slow (3-5x slower)

Runtime decompression:
Both:          Fast (same speed)

Recommendation: Use Brotli for static assets (pre-compress at build time), Gzip as fallback.

Server Configuration

Nginx

# Enable Gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;  # 6 is good balance
gzip_types
  text/plain
  text/css
  text/xml
  text/javascript
  application/json
  application/javascript
  application/xml+rss
  application/rss+xml
  font/truetype
  font/opentype
  application/vnd.ms-fontobject
  image/svg+xml;

# Enable Brotli (requires ngx_brotli module)
brotli on;
brotli_comp_level 6;
brotli_types
  text/plain
  text/css
  text/xml
  text/javascript
  application/json
  application/javascript
  application/xml+rss
  application/rss+xml
  font/truetype
  font/opentype
  application/vnd.ms-fontobject
  image/svg+xml;

# Serve pre-compressed files
location ~* \.(js|css|svg|json)$ {
  gzip_static on;
  brotli_static on;
}

Apache

# .htaccess
<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE text/javascript
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/json
  AddOutputFilterByType DEFLATE image/svg+xml
  AddOutputFilterByType DEFLATE font/truetype
  AddOutputFilterByType DEFLATE font/opentype
</IfModule>

# Brotli (requires mod_brotli)
<IfModule mod_brotli.c>
  AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css text/javascript application/javascript application/json image/svg+xml
</IfModule>

Next.js (Vercel/Netlify)

Compression is automatic on Vercel and Netlify. For custom servers:

// next.config.js
module.exports = {
  compress: true,  // Enables Gzip
};

// For Brotli with custom server
const compression = require('compression');
const express = require('express');
const next = require('next');

const app = next({ dev: false });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  const server = express();
  
  // Enable compression
  server.use(compression({
    brotli: {
      enabled: true,
      zlib: {},
    },
  }));

  server.all('*', (req, res) => handle(req, res));
  server.listen(3000);
});

Build-Time Compression

Next.js Plugin

// next.config.js
const CompressionPlugin = require('compression-webpack-plugin');
const zlib = require('zlib');

module.exports = {
  webpack: (config, { isServer }) => {
    if (!isServer) {
      config.plugins.push(
        // Gzip
        new CompressionPlugin({
          filename: '[path][base].gz',
          algorithm: 'gzip',
          test: /\.(js|css|html|svg)$/,
          threshold: 1024,  // Only compress files > 1KB
          minRatio: 0.8,
        }),
        
        // Brotli
        new CompressionPlugin({
          filename: '[path][base].br',
          algorithm: 'brotliCompress',
          test: /\.(js|css|html|svg)$/,
          compressionOptions: {
            params: {
              [zlib.constants.BROTLI_PARAM_QUALITY]: 11,
            },
          },
          threshold: 1024,
          minRatio: 0.8,
        })
      );
    }
    return config;
  },
};

Vite

// vite.config.js
import viteCompression from 'vite-plugin-compression';

export default {
  plugins: [
    // Gzip
    viteCompression({
      algorithm: 'gzip',
      ext: '.gz',
      threshold: 1024,
    }),
    
    // Brotli
    viteCompression({
      algorithm: 'brotliCompress',
      ext: '.br',
      threshold: 1024,
    }),
  ],
};

Webpack

// webpack.config.js
const CompressionPlugin = require('compression-webpack-plugin');
const zlib = require('zlib');

module.exports = {
  plugins: [
    new CompressionPlugin({
      filename: '[path][base].gz',
      algorithm: 'gzip',
      test: /\.(js|css|html|svg)$/,
      threshold: 1024,
      minRatio: 0.8,
    }),
    
    new CompressionPlugin({
      filename: '[path][base].br',
      algorithm: 'brotliCompress',
      test: /\.(js|css|html|svg)$/,
      compressionOptions: {
        params: {
          [zlib.constants.BROTLI_PARAM_QUALITY]: 11,
        },
      },
      threshold: 1024,
      minRatio: 0.8,
    }),
  ],
};

What to Compress

✅ Compress These

Text files:
- HTML (.html)
- CSS (.css)
- JavaScript (.js, .mjs)
- JSON (.json)
- XML (.xml)
- SVG (.svg)
- Fonts (.ttf, .otf, .eot) - Not .woff/.woff2 (already compressed)

Text formats typically compress well (70-90% reduction)

❌ Don't Compress These

Already compressed:
- Images: JPEG, PNG, WebP, AVIF, GIF
- Videos: MP4, WebM
- Fonts: WOFF, WOFF2
- Archives: ZIP, RAR, 7Z

These won't compress further and may even grow larger.

Content Negotiation

The server should automatically serve the best format the client supports:

Client request:
Accept-Encoding: gzip, deflate, br

Server response:
Content-Encoding: br
Vary: Accept-Encoding

Implementation

// Express middleware
const compression = require('compression');

app.use(compression({
  // Only compress responses larger than 1KB
  threshold: 1024,
  
  // Decide whether to compress based on request/response
  filter: (req, res) => {
    if (req.headers['x-no-compression']) {
      return false;
    }
    return compression.filter(req, res);
  },
  
  // Compression level (1-9 for Gzip, 0-11 for Brotli)
  level: 6,
}));

Dynamic vs Static Compression

Static (Pre-compressed)

# Compress at build time
for file in dist/**/*.{js,css,html,svg}; do
  gzip -k -9 "$file"
  brotli -k -q 11 "$file"
done

Pros: Highest compression, no CPU cost at runtime
Cons: Larger build size, more storage

Dynamic (On-the-fly)

Pros: Less storage, automatic for all responses
Cons: CPU cost, lower compression levels (for speed)

Best Practice: Static for assets, dynamic for HTML/API responses.

CDN Compression

Most CDNs handle compression automatically:

Cloudflare

  • Automatic Gzip and Brotli
  • Enabled by default
  • No configuration needed

AWS CloudFront

// CloudFormation
"ViewerProtocolPolicy": "redirect-to-https",
"Compress": true,  // Enable compression

Fastly

# VCL configuration
if (req.http.Accept-Encoding) {
  if (req.http.Accept-Encoding ~ "br") {
    set req.http.Accept-Encoding = "br";
  } elsif (req.http.Accept-Encoding ~ "gzip") {
    set req.http.Accept-Encoding = "gzip";
  }
}

Testing Compression

Check if Compression is Enabled

# Check headers
curl -I -H "Accept-Encoding: gzip, br" https://example.com

# Should see:
Content-Encoding: br
# or
Content-Encoding: gzip

Compare Sizes

# Original size
curl https://example.com/bundle.js -o bundle.js
ls -lh bundle.js

# Compressed size (Gzip)
curl -H "Accept-Encoding: gzip" https://example.com/bundle.js -o bundle.js.gz
ls -lh bundle.js.gz

# Compressed size (Brotli)
curl -H "Accept-Encoding: br" https://example.com/bundle.js -o bundle.js.br
ls -lh bundle.js.br

Browser DevTools

Network tab:
- Size: Transferred size (compressed)
- Content: Actual size (uncompressed)

Example:
Size: 50 KB (compressed with Brotli)
Content: 250 KB (original size)
Savings: 80%

Compression Levels

Gzip Levels (1-9)

Level 1:  Fast compression, ~60% reduction
Level 6:  Balanced (default), ~75% reduction
Level 9:  Best compression, ~78% reduction

Build time:
Level 1:  1x
Level 6:  3x
Level 9:  5x

Recommendation: Level 6 for dynamic, Level 9 for static

Brotli Levels (0-11)

Level 4:   Fast, ~75% reduction
Level 6:   Balanced, ~80% reduction
Level 11:  Best, ~82% reduction

Build time:
Level 4:   1x
Level 6:   3x
Level 11:  10x

Recommendation: Level 6 for dynamic, Level 11 for static

Best Practices

  1. Enable Both: Brotli with Gzip fallback
  2. Pre-compress: Static assets at build time
  3. High Levels: Use max compression for static files
  4. Skip Small Files: Don't compress < 1KB files
  5. Vary Header: Include Vary: Accept-Encoding
  6. CDN: Let CDN handle compression
  7. Don't Double-Compress: Skip already-compressed formats
  8. Test: Verify compression in production
  9. Monitor: Track compression ratios
  10. Cache: Cache compressed responses

Common Pitfalls

Compressing images: Already compressed
Compress text files only

No Vary header: Cache issues
Always include Vary: Accept-Encoding

Low levels: 30% vs 80% savings
High levels for static assets

Dynamic Brotli 11: Too slow
Brotli 4-6 for dynamic, 11 for static

No fallback: Breaks old browsers
Brotli + Gzip fallback

Compression is the easiest performance win—enable it everywhere!

On this page