Cache-Control headers are present
Why it matters
Without Cache-Control headers, browsers fall back to heuristic caching — typically caching responses for 10% of their apparent age, or not at all. Every repeat visitor re-downloads content that hasn't changed, wasting bandwidth and adding latency on every navigation. Properly configured caching reduces server load, speeds up repeat visits, and improves CDN hit rates. ISO 25010 performance-efficiency identifies caching as a core mechanism for resource utilization. The absence of cache headers forces both browsers and CDNs into conservative or undefined behavior, leaving significant performance on the table.
Severity rationale
Medium because missing cache headers cause preventable latency on repeat visits and increase server load, but the site remains functional — users are slowed, not blocked.
Remediation
Set Cache-Control explicitly on every response type. Match the directive to the content's mutability:
# Static assets (images, fonts, versioned JS/CSS)
add_header Cache-Control "public, max-age=31536000, immutable" always;
# HTML pages (content changes; revalidate)
add_header Cache-Control "public, max-age=3600, must-revalidate" always;
# Authenticated or personalized pages
add_header Cache-Control "private, no-store" always;
In Next.js API routes: res.setHeader('Cache-Control', 'public, max-age=3600, s-maxage=86400'). For app/ router, use export const revalidate = 3600 in route segments. Confirm with curl -sI https://yoursite.com | grep -i cache-control.
Detection
-
ID:
cache-headers -
Severity:
medium -
What to look for: Extract the
Cache-Controlheader value from the final document response. Count the number of cache directives present (e.g.,max-age,s-maxage,no-cache,no-store,public,private,must-revalidate). Parse anymax-ageors-maxagevalue to determine the cache duration in seconds. -
Pass criteria: A
Cache-Controlheader is present on the main document response with at least 1 recognized cache directive. The header value must not be empty. Report the directive(s) found and themax-agevalue if present (e.g., "Cache-Control: public, max-age=3600 — 1 hour cache"). -
Fail criteria: No
Cache-Controlheader on the main document response, or the header value is empty. -
Skip (N/A) when: The response includes
Set-Cookieheaders, as caching responses with cookies can leak user data and servers may intentionally omit caching in this case. -
Detail on fail:
"No Cache-Control header on main document — browsers cannot cache optimally" -
Remediation: Cache-Control headers let browsers and CDNs cache responses, reducing load times on repeat visits. Add appropriate caching for your content:
# Static marketing pages — cache for 1 hour, revalidate Cache-Control: public, max-age=3600, must-revalidate # Dynamic app pages — no cache Cache-Control: no-storeIn Next.js, static pages get caching automatically. For custom headers, use
next.config.jsheaders()or set them in API routes:res.setHeader('Cache-Control', 'public, max-age=3600'). Verify with:curl -sI {URL} | grep -i cache-control
External references
- iso-25010:2011 · performance-efficiency.time-behaviour — Time Behaviour — Cache-Control headers minimize repeat-visit latency
Taxons
History
- 2026-04-18·v1.0.0·Initial import from site-health-check·automated