Skip to main content

Cache Policy.

Performance Asset Optimization

Long cache TTLs prevent re-downloading unchanged assets

What does this check test?

This check evaluates the HTTP caching headers (`Cache-Control`, `ETag`, `Expires`, `Last-Modified`) on static resources to ensure they are configured for efficient caching. Proper cache policies allow browsers to reuse previously downloaded resources instead of re-downloading them on every visit. Lighthouse flags static resources with cache TTLs shorter than 30 days. An effective caching strategy uses content-hashed filenames (e.g., `app.a1b2c3.js`) with long cache TTLs (`max-age=31536000`), so files are cached until their content changes.

Why does it matter?

Without proper caching, every page visit requires re-downloading all resources — CSS, JavaScript, images, and fonts — even if they have not changed. This wastes bandwidth, increases server load, and makes repeat visits just as slow as the first visit. Effective caching can make repeat page loads nearly instant (sub-second) because all resources are served from the local cache. For sites where users visit multiple pages or return frequently, caching is one of the most impactful performance optimizations. CDNs also rely on cache headers to know how long to cache your resources at the edge.

Who is affected?

All websites benefit from proper caching, but sites with repeat visitors (SaaS dashboards, web applications, news sites, e-commerce) see the greatest impact. Sites that deploy frequently need cache-busting strategies (content hashing) to ensure users get updated assets without sacrificing cache duration. Sites with many static assets (images, fonts, JavaScript bundles) have the most to gain from long cache TTLs.

Where does this apply?

Inspect the `Cache-Control`, `ETag`, `Expires`, and `Last-Modified` response headers for each resource in Chrome DevTools Network panel. Resources without cache headers, or with `Cache-Control: no-cache` or `max-age=0`, are re-downloaded on every visit. The 'Size' column shows '(disk cache)' or '(memory cache)' for cached resources — if resources show actual byte values on repeat visits, caching is not working.

How to fix it

Set long cache TTLs on content-hashed static assets and short TTLs on HTML. Configure caching by resource type in Nginx:
nginx
# Immutable hashed assets — cache for 1 year
location ~* \.(js|css|png|webp|woff2)$ {
  expires 1y;
  add_header Cache-Control "public, immutable";
}

# HTML pages — always revalidate
location / {
  add_header Cache-Control "no-cache";
}
Generate content-hashed filenames in webpack:
js
// webpack.config.js
module.exports = {
  output: {
    filename: '[name].[contenthash].js',
    assetModuleFilename: '[name].[contenthash][ext]',
  },
};
For API responses: `Cache-Control: private, max-age=0, must-revalidate` with `ETag` for conditional requests. Use `stale-while-revalidate` for assets that should update eventually: `Cache-Control: max-age=3600, stale-while-revalidate=86400`. Never set long cache TTLs on non-hashed filenames — users will be stuck with stale content.

References

AppVet checks Cache Policy automatically

Run a free performance scan and get a full report with actionable fixes, including a Fix with AI prompt you can paste into any coding tool.

Run Audit