Compression Headers Analyzer
| Analyzer ID | Category | Severity | Time To Fix |
|---|---|---|---|
compression-headers | ⚡ Performance | Medium | 30 minutes |
What This Checks
Verifies that your web server returns compressed responses for static assets like JavaScript, CSS, and HTML files. Recognised encodings are gzip, br (brotli), zstd (zstandard), and deflate.
Checks for:
Content-Encodingresponse header present on JS and CSS assets- A recognised compression encoding (
gzip,br,zstd,deflate) - Correct
Accept-Encodingnegotiation (brotli is only advertised on HTTPS sites)
Note: Brotli (
br) is only negotiated over HTTPS. The analyzer reflects this: brotli is only checked on HTTPS sites.
Why It Matters
- Bandwidth Reduction: Compression reduces transfer size by 60-90% for text-based assets, directly cutting hosting costs
- Faster Load Times: Smaller files download faster, especially on slow or mobile connections. Gzip cuts JS by ~70%, brotli by ~75%
- Core Web Vitals: Faster asset delivery improves LCP and FID scores, which affect SEO rankings
- Production Critical: Uncompressed assets are one of the easiest performance wins to miss in server configuration
How to Fix
Quick Fix (5 minutes)
Enable gzip in your web server with the minimum required configuration:
Nginx:
# /etc/nginx/nginx.conf
http {
gzip on;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
gzip_min_length 1000;
}Apache:
sudo a2enmod deflate
sudo systemctl restart apache2# .htaccess or httpd.conf
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json
</IfModule>CDN (no server config needed): Most CDNs compress automatically. Enable "Compress Objects Automatically" in AWS CloudFront, or verify it is on in Cloudflare's Speed settings.
Proper Fix (30 minutes)
For full compression coverage including brotli (HTTPS only) and pre-compressed asset serving:
Nginx - gzip + brotli:
http {
# Gzip (all connections)
gzip on;
gzip_vary on;
gzip_min_length 1000;
gzip_comp_level 6;
gzip_proxied any;
gzip_types
text/plain text/css text/javascript
application/json application/javascript application/x-javascript
application/xml application/xml+rss
font/ttf font/otf font/woff font/woff2
image/svg+xml;
# Brotli (requires ngx_brotli module — HTTPS only in browsers)
brotli on;
brotli_comp_level 6;
brotli_types
text/plain text/css text/javascript
application/json application/javascript application/x-javascript
application/xml font/ttf font/woff font/woff2
image/svg+xml;
}Install brotli module for Nginx:
# Ubuntu/Debian
sudo apt-get install libnginx-mod-brotli
# Alpine (Docker)
apk add --no-cache nginx-mod-http-brotliApache - mod_deflate + mod_brotli:
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css
AddOutputFilterByType DEFLATE text/javascript application/javascript
AddOutputFilterByType DEFLATE application/json application/xml
AddOutputFilterByType DEFLATE font/ttf font/woff font/woff2 image/svg+xml
DeflateCompressionLevel 6
</IfModule>
# Apache 2.4.26+ only
<IfModule mod_brotli.c>
AddOutputFilterByType BROTLI_COMPRESS text/html text/css
AddOutputFilterByType BROTLI_COMPRESS text/javascript application/javascript
AddOutputFilterByType BROTLI_COMPRESS application/json application/xml
AddOutputFilterByType BROTLI_COMPRESS font/ttf font/woff font/woff2 image/svg+xml
</IfModule>Serve pre-compressed assets (maximum performance):
Build pre-compressed versions during your asset pipeline:
// webpack.mix.js
const CompressionPlugin = require('compression-webpack-plugin');
mix.webpackConfig({
plugins: [
new CompressionPlugin({ algorithm: 'gzip', test: /\.(js|css|svg)$/ }),
new CompressionPlugin({ algorithm: 'brotliCompress', test: /\.(js|css|svg)$/, filename: '[path][base].br' }),
],
});Then tell Nginx to serve them directly instead of compressing on the fly:
location ~* \.(js|css)$ {
gzip_static on;
brotli_static on;
}Verify compression is working:
curl -H "Accept-Encoding: gzip, br" -I https://yoursite.com/js/app.js
# Look for: Content-Encoding: gzip (or br)ShieldCI Configuration
This analyzer is automatically skipped in CI environments ($runInCI = false) and only runs in production and staging environments.
Why skip in CI and development?
- Compression is a web server configuration and cannot be verified without a running server
- Local and CI environments typically serve assets without a web server in front of them
- Production and staging should have a properly configured web server (Nginx, Apache, or CDN)
Environment Detection: The analyzer checks your Laravel APP_ENV setting and only runs when it maps to production or staging. Custom environment names can be mapped in config/shieldci.php:
// config/shieldci.php
'environment_mapping' => [
'production-us' => 'production',
'production-blue' => 'production',
'staging-preview' => 'staging',
],References
Related Analyzers
- CDN Configuration Analyzer - Ensures CDN is configured
- Asset Minification Analyzer - Ensures assets are minified before compression
- Cache Headers Analyzer - Ensures proper cache headers are set