Cache-Control Headers
Set the right Cache-Control headers on your origin for optimal caching with ModPageSpeed 2.0.
Requires ModPageSpeed 2.0.x or later with conditional revalidation support. Without conditional revalidation,
must-revalidatecauses full origin re-fetches on every stale request. Upgrade before following these recommendations.
Your origin’s Cache-Control headers directly control how ModPageSpeed caches
and serves your content. Getting these right eliminates stale content surprises
and minimizes unnecessary origin traffic.
When your origin sends no Cache-Control header, ModPageSpeed applies
configurable defaults (HTML: no-cache, CSS/JS: 300s, images: 3600s) and logs
a warning. Setting explicit headers is better than relying on defaults.
Recommended Headers by Content Type
HTML Pages
Cache-Control: public, max-age=60, must-revalidate
ETag: "content-hash-or-version"
HTML references hashed assets. A deploy changes HTML content to point at new
asset URLs. Short max-age=60 provides one minute of caching. With conditional
revalidation, stale requests are cheap — origin returns 304 when content hasn’t
changed.
Use max-age=0 only when absolute real-time freshness is required (stock
tickers, live scores). Every request with max-age=0 triggers a conditional
revalidation, which means an origin round-trip even when content hasn’t changed.
Hashed Static Assets (CSS/JS with Fingerprints)
Cache-Control: public, max-age=31536000, immutable
The URL changes on every build. Content at a given URL never changes.
ModPageSpeed respects immutable and caps the max-age at
pagespeed_immutable_max_age (default: 7 days).
Non-Hashed Static Assets
Cache-Control: public, max-age=3600, must-revalidate
ETag: "file-mtime-and-size"
The URL is stable but content may change. Short max-age with must-revalidate
keeps content fresh. Conditional revalidation makes the revalidation cheap.
User-Uploaded Images
Cache-Control: public, max-age=86400
User images rarely change at the same URL. 24-hour caching is reasonable.
If images can be replaced at the same URL, add must-revalidate and an ETag.
API Responses and Dynamic Content
Cache-Control: no-store
ModPageSpeed does not cache no-store responses. The response passes through
unchanged.
Framework Configuration
| Framework | Where to Set Headers | HTML | Hashed Assets |
|---|---|---|---|
| nginx (static) | nginx.conf per location | max-age=60, must-revalidate | max-age=31536000, immutable |
| Apache | .htaccess Header set | max-age=60, must-revalidate | max-age=31536000, immutable |
| Next.js 13+ | next.config.js headers() | max-age=60, must-revalidate | Automatic for _next/static/ |
| Astro 4+ | Server adapter headers | max-age=60, must-revalidate | Automatic via content hashing |
| Rails 7+ | config.public_file_server.headers | max-age=60, must-revalidate | Automatic via Propshaft |
| WordPress | Cache plugin or .htaccess | max-age=60, must-revalidate | Theme-dependent |
PURGE vs Natural Expiration
PURGE immediately invalidates all cached variants for a URL. Use it for
urgent content corrections. For routine deploys, let must-revalidate handle
freshness naturally — conditional revalidation is cheaper than purge-and-rebuild
because it preserves optimized image variants (AVIF, WebP) when only the HTML
changed.
ModPageSpeed Directives
These directives control the default max-age values applied when origin
responses lack a Cache-Control header. They do not override explicit
origin headers.
pagespeed_html_max_age 0; # Default for HTML (seconds, default: 0 = no-cache)
pagespeed_css_max_age 300; # Default for CSS/JS (seconds, default: 300)
pagespeed_image_max_age 3600; # Default for images (seconds, default: 3600)
When pagespeed_html_max_age is 0 and the origin sends no Cache-Control,
HTML responses are served with Cache-Control: no-cache — the client must
revalidate on every request.
Conditional Revalidation
pagespeed_conditional_revalidation on; # default: on
When enabled, stale cache entries with stored ETag or Last-Modified values
trigger conditional requests (If-None-Match / If-Modified-Since) instead of
full re-fetches. On 304, the cached content is refreshed without re-downloading
or re-optimizing. Disable only if your origin mishandles conditional requests.
Auditing Your Origin
The web console flags URLs where the origin sends no Cache-Control
header. Use the URL inspector to check freshness status and identify origins that
need explicit headers.