This page demonstrates different caching strategies for static assets.
Cache-Control: no-store
Re-downloaded every time
Cache-Control: public, max-age=31536000, immutable
Cached for 1 year
stale-while-revalidate
Cached with background refresh
Check: asset-caching (automatic, detection not yet implemented)
Status: Future Issue
Detection logic would need to:
// For versioned static assets (with hash in filename) Cache-Control: public, max-age=31536000, immutable // Cached for 1 year, won't be revalidated // For frequently changing assets Cache-Control: public, max-age=3600 // Cached for 1 hour // With stale-while-revalidate (modern, best UX) Cache-Control: public, max-age=3600, stale-while-revalidate=86400 // Serve stale for 24h while fetching fresh version // For private user data Cache-Control: private, max-age=0, must-revalidate // Cached by browser only, always revalidate
// Disables all caching (BAD for static assets) Cache-Control: no-store, no-cache, must-revalidate // No cache header at all (BAD) (missing Cache-Control header) // max-age=0 for static assets (BAD) Cache-Control: public, max-age=0
| Asset Type | Recommended Cache-Control |
|---|---|
| Versioned assets (CSS, JS with hash) | public, max-age=31536000, immutable |
| Images, fonts | public, max-age=31536000 |
| HTML pages | public, max-age=3600, stale-while-revalidate=86400 |
| API responses (dynamic) | private, max-age=0, must-revalidate |
| User-specific data | private, no-store |
In Next.js API routes:
export async function GET() {
return new Response(assetData, {
headers: {
'Content-Type': 'image/png',
'Cache-Control': 'public, max-age=31536000, immutable',
}
})
}In Next.js config for static files:
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/static/:path*',
headers: [
{
key: 'Cache-Control',
value: 'public, max-age=31536000, immutable',
},
],
},
]
},
}curl -I https://example.com/asset.png