Skip to main content
mod_pagespeed 2.1 is here — open source (Apache-2.0): the module you know, plus the optimizer worker

Set Cache-Control headers

Which Cache-Control headers to set on your origin, by content type and by framework, for correct caching with ModPageSpeed 2.0.

On this page

Requires ModPageSpeed 2.0.x or later with conditional revalidation support. Without conditional revalidation, must-revalidate causes 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 prevents stale content and cuts unnecessary origin traffic.

When your origin sends no Cache-Control header, ModPageSpeed applies configurable defaults (HTML: no-cache, CSS/JS: 300s, images: 1800s in safe mode) and logs a warning. Explicit headers are better than relying on these fallback TTLs.

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 strips immutable from its transformed output — the optimized bytes depend on mutable config and software version — but preserves the long TTL, capping 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

FrameworkWhere to Set HeadersHTMLHashed Assets
nginx (static)nginx.conf per locationmax-age=60, must-revalidatemax-age=31536000, immutable
Apache.htaccess Header setmax-age=60, must-revalidatemax-age=31536000, immutable
Next.js 13+next.config.js headers()max-age=60, must-revalidateAutomatic for _next/static/
Astro 4+Server adapter headersmax-age=60, must-revalidateAutomatic via content hashing
Rails 7+config.public_file_server.headersmax-age=60, must-revalidateAutomatic via Propshaft
WordPressCache plugin or .htaccessmax-age=60, must-revalidateTheme-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 — conditional revalidation is cheaper than purge-and-rebuild because it preserves optimized image variants (AVIF, WebP) when only the HTML changed. See 304 conditional revalidation vs PURGE for when each is the right invalidation strategy.

Cache Mode

The pagespeed_cache_mode directive controls how ModPageSpeed assembles Cache-Control headers on optimized responses. Safe mode (the default) adds must-revalidate and uses short TTLs for quick recovery from misconfigurations. Aggressive mode uses long TTLs with public for maximum cache efficiency. See Cache Modes for full details, or the safety math behind must-revalidate vs aggressive TTLs for how each mode trades freshness against origin load.

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 1800;  # Default for images (seconds, safe: 1800, aggressive: 86400)

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.

Browser Force-Refresh

pagespeed_force_refresh_html on;   # default: on
pagespeed_force_refresh off;       # default: off

When a user performs a force-refresh (Ctrl+F5 or Shift+Reload), the browser sends Cache-Control: no-cache or Pragma: no-cache. ModPageSpeed detects these signals and forces revalidation against your origin, even if the cached entry is fresh.

For HTML, this is enabled by default — users expect force-refresh to fetch the latest page. For images, CSS, and JS, it is off by default to prevent unnecessary origin load. Enable pagespeed_force_refresh if you want force-refresh to apply to all content types.

When conditional revalidation is also enabled (the default), force-refresh uses If-None-Match / If-Modified-Since to avoid re-downloading unchanged content.

Cache-extension filters

The filters in this section belong to the in-process module on Apache, nginx and IIS. They extend browser cache lifetimes and manage resource URLs across domains. Browsers cache resources for a year, but pick up updated content the moment a resource changes, because the URL carries a content hash. The extend_cache CoreFilter drives this: it sets a 1-year cache lifetime on CSS, JS, and image URLs.

extend_cache

Core filter. Rewrites resource URLs (CSS, JS, images) to include a content hash, then serves the optimized resource with a 1-year Cache-Control: max-age header. When the original resource changes, the hash changes, generating a new URL that bypasses the browser cache.

Resources that previously had short or no cache lifetimes gain a 1-year cache lifetime. Because the URL carries the content hash, a changed resource gets a new URL and is never served stale.

The sub-filters extend_cache_css, extend_cache_images, and extend_cache_scripts are included when you enable extend_cache, which turns on all three. Each can also be enabled individually with EnableFilters (for example, extend_cache_images alone).

extend_cache_pdfs

Not a CoreFilter. Applies the same content-hash-based cache extension to PDF file links. Enable this filter if your site serves PDFs that change infrequently.

# Apache
ModPagespeedEnableFilters extend_cache_pdfs
# Nginx
pagespeed EnableFilters extend_cache_pdfs;

rewrite_domains

Not a CoreFilter. Test before deploying. Rewrites resource URLs to use domains specified by MapRewriteDomain or ShardDomain directives. Useful for CDN integration or domain sharding.

# Apache
ModPagespeedEnableFilters rewrite_domains
# Nginx
pagespeed EnableFilters rewrite_domains;

This filter only affects resources that mod_pagespeed does not otherwise optimize. Resources already rewritten by other filters (rewrite_css, rewrite_images, etc.) already have their domains set by those filters.

See Domain Configuration for MapRewriteDomain and ShardDomain setup.

local_storage_cache

Experimental. Stores inlined CSS and JavaScript in the browser’s localStorage on first visit, then loads from localStorage on subsequent visits instead of re-inlining. This reduces HTML payload on repeat views at the cost of JavaScript complexity and reliance on localStorage availability.

# Apache
ModPagespeedEnableFilters local_storage_cache
# Nginx
pagespeed EnableFilters local_storage_cache;

Not recommended for most deployments. Browser localStorage has size limits (typically 5-10 MB per origin) and can be cleared by the user at any time. Sites with many inlined resources may exceed these limits. Since v1.15.0+r18, with HonorCsp (default on) the filter stands down on pages whose Content-Security-Policy disallows the inline script it relies on.

On IIS the same directives use the syntax described in IIS configuration.

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.