Introduction
Caching is the most effective performance optimization available. A cached resource loads instantly — zero network requests, zero server processing, zero latency.
Web caching operates at multiple layers: browser cache, service workers, CDN edge cache, and server-side cache. Getting them right means near-instant repeat visits.
This guide covers caching at every layer with practical configurations you can apply immediately.
Key Concepts
HTTP Cache Headers
# Immutable assets (hashed filenames)
Cache-Control: public, max-age=31536000, immutable
# HTML pages (always revalidate)
Cache-Control: no-cache
# API responses
Cache-Control: public, max-age=60, stale-while-revalidate=300
# Never cache
Cache-Control: no-store
Stale-While-Revalidate
SWR serves cached content immediately while fetching a fresh version in the background. Users get instant responses while the cache stays fresh.
Practical Examples
1. Next.js Caching Headers
module.exports = {
async headers() {
return [
{
source: '/:all*(svg|jpg|png|webp|avif)',
headers: [{ key: 'Cache-Control', value: 'public, max-age=31536000, immutable' }],
},
{
source: '/api/:path*',
headers: [{ key: 'Cache-Control', value: 'public, s-maxage=60, stale-while-revalidate=300' }],
},
];
},
};
2. Service Worker Cache Strategy
self.addEventListener('fetch', (event) => {
const { request } = event;
if (request.url.includes('/api/')) {
event.respondWith(
fetch(request).then(resp => {
caches.open('v1').then(c => c.put(request, resp.clone()));
return resp;
}).catch(() => caches.match(request))
);
} else {
event.respondWith(caches.match(request).then(c => c || fetch(request)));
}
});
3. Nginx Configuration
location ~* \.(js|css|png|jpg|svg|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location ~* \.html$ {
add_header Cache-Control "no-cache";
}
Best Practices
- ✅ Use content hashes in filenames for long-term caching
- ✅ Set immutable on hashed assets
- ✅ Use stale-while-revalidate for API data
- ✅ Always revalidate HTML with no-cache
- ✅ Version your service worker caches
- ❌ Don't set long max-age on URLs that can change
- ❌ Don't confuse no-cache with no-store
Common Pitfalls
- 🚫 Caching HTML with max-age — users get stale pages
- 🚫 Forgetting s-maxage for CDNs
- 🚫 Not busting cache on deployment
- 🚫 Over-caching user-specific data — use private, not public