Caching Static Assets (CSS, JS, Images)
Best practices for caching static assets with long max-age, content hashing, and the immutable directive. Maximize cache hit rates while enabling instant updates.
Detailed Explanation
Static Asset Caching Strategy
Static assets (CSS, JavaScript, images, fonts, videos) are the easiest resources to cache aggressively because they change only when you deploy new code.
The Recommended Header
Cache-Control: public, max-age=31536000, immutable
This tells every cache (browser, CDN, proxy): "Cache this for 1 year and don't even revalidate on reload."
Why 1 Year?
31536000 seconds (365 days) is the maximum recommended value per RFC 2616. In practice, browser caches are limited in size and may evict entries sooner, but setting 1 year ensures the resource stays cached as long as possible.
Content Hashing Makes It Safe
Modern build tools generate filenames with content hashes:
app-BkQ3x9f2.js (Vite)
app.a1b2c3d4.chunk.js (webpack)
styles-Hx8n4p1m.css (esbuild)
When you change the source code, a new hash is generated, producing a new filename. The old file at the old URL never changes — so max-age=31536000 is perfectly safe.
Implementation by File Type
| File Type | Header | Notes |
|---|---|---|
| Hashed JS/CSS | public, max-age=31536000, immutable |
Content-hash filename |
| Unhashed JS/CSS | public, max-age=0, must-revalidate |
Requires ETag support |
| Images (hashed) | public, max-age=31536000, immutable |
Content-hash filename |
| Images (unhashed) | public, max-age=86400 |
Accept 1-day staleness |
| Fonts | public, max-age=31536000, immutable |
Rarely change |
| Favicon | public, max-age=86400 |
Changes are rare but possible |
Server Configuration (Nginx)
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
Use Case
A production React application serves 2MB of JavaScript and CSS bundles. With 'public, max-age=31536000, immutable', returning users load the app from cache in under 100ms. New deployments change the content hash, so users automatically download the new version on their next visit. This setup reduces CDN bandwidth by 95% for returning visitors and makes the app feel instant on repeat visits.