CACHE-002 recommended Static Asset Caching

Content hashes for cache invalidation

Asset filenames include content hashes enabling long TTLs with automatic invalidation on changes

Question to ask

"Do users need to hard-refresh to get your latest deploy?"

Verification guide

Severity: Recommended

Static asset filenames should include content hashes (e.g., main.a1b2c3d4.js). This enables aggressive caching while ensuring users always get the latest version when code changes.

Check automatically:

  1. Check build output for hashed filenames:
# Look for hash patterns in dist/build folder
ls -la dist/assets/ 2>/dev/null | grep -E '\.[a-f0-9]{6,}\.(js|css)$'

# Or in Next.js
ls -la .next/static/chunks/ 2>/dev/null | head -5

# Or in Vite
ls -la dist/assets/ 2>/dev/null | head -5
  1. Check HTML references for hashed assets:
# Extract script/link tags and check for hashes
curl -sL https://example.com | grep -oE '(src|href)="[^"]*\.[a-f0-9]{6,}\.(js|css)"' | head -5
  1. Check build config for content hashing:
# Vite (default enabled)
grep -r "build" vite.config.* 2>/dev/null | grep -i hash

# Webpack
grep -rE "contenthash|chunkhash" webpack.config.* 2>/dev/null

# Next.js (enabled by default, no config needed)

Cross-reference with:

  • CACHE-001 (hashed assets should have immutable/long-TTL cache headers)

Pass criteria:

  • JS and CSS filenames include content hashes (e.g., main.a1b2c3d4.js)
  • HTML references updated on each build to point to new hashes
  • Cache-Control set to long TTL (1 year) or immutable since hash handles invalidation

Fail criteria:

  • Static assets use fixed filenames (main.js, styles.css)
  • Query string cache busting only (main.js?v=123) - less reliable
  • No build pipeline (hand-editing JS/CSS files)

Evidence to capture:

  • Sample hashed filenames from build output
  • Build tool used (Vite, Webpack, Next.js, etc.)
  • Cache-Control header on hashed assets

Section

21. Caching

Infrastructure Features