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.gzBrotli (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.brComparison
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-EncodingImplementation
// 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"
donePros: 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 compressionFastly
# 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: gzipCompare 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.brBrowser 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 staticBrotli 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 staticBest Practices
- Enable Both: Brotli with Gzip fallback
- Pre-compress: Static assets at build time
- High Levels: Use max compression for static files
- Skip Small Files: Don't compress < 1KB files
- Vary Header: Include
Vary: Accept-Encoding - CDN: Let CDN handle compression
- Don't Double-Compress: Skip already-compressed formats
- Test: Verify compression in production
- Monitor: Track compression ratios
- 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!