The Cache-Control header tells browsers and CDNs how to cache responses.
Proper caching dramatically improves performance by avoiding unnecessary network requests.
Caching is set by the server in response headers. The client can also send
Cache-Control to request fresh data.
Common Cache-Control Directives
| Directive |
Description |
Example Use |
max-age=N |
Cache for N seconds |
Static assets, API responses |
no-cache |
Must revalidate before using cache |
HTML pages, user-specific data |
no-store |
Never cache (sensitive data) |
Bank statements, passwords |
private |
Only browser can cache (not CDN) |
User profiles, dashboards |
public |
Any cache can store (CDN-friendly) |
Images, CSS, JS bundles |
immutable |
Never changes, don't revalidate |
Versioned assets (app.abc123.js) |
stale-while-revalidate=N |
Serve stale while fetching fresh |
Background updates |
Server: Setting Cache Headers (Node.js)
import { createServer } from 'node:http';
import { readFile } from 'node:fs/promises';
const server = createServer(async (req, res) => {
const url = req.url;
if (url.match(/\.(js|css|png|jpg|woff2)$/)) {
const file = await readFile(`./public${url}`);
res.writeHead(200, {
'Content-Type': getMimeType(url),
'Cache-Control': 'public, max-age=31536000, immutable'
});
res.end(file);
return;
}
if (url.endsWith('.html') || url === '/') {
const html = await readFile('./public/index.html');
res.writeHead(200, {
'Content-Type': 'text/html',
'Cache-Control': 'no-cache'
});
res.end(html);
return;
}
if (url.startsWith('/api/')) {
res.writeHead(200, {
'Content-Type': 'application/json',
'Cache-Control': 'public, max-age=60, stale-while-revalidate=300'
});
res.end(JSON.stringify({ data: '...' }));
return;
}
if (url.startsWith('/user/')) {
res.writeHead(200, {
'Content-Type': 'application/json',
'Cache-Control': 'private, max-age=0, must-revalidate'
});
res.end(JSON.stringify({ user: '...' }));
}
});
server.listen(3000);
Common Caching Strategies
'Cache-Control: public, max-age=31536000, immutable'
'Cache-Control: no-cache'
'Cache-Control: public, max-age=60, stale-while-revalidate=600'
'Cache-Control: private, max-age=0'
'Cache-Control: no-store'
'Cache-Control: public, max-age=60, s-maxage=3600'
Client: Requesting Fresh Data
const response = await fetch('/api/data', {
cache: 'no-store'
});
async function fetchFresh(url) {
return fetch(url, { cache: 'no-store' });
}
async function fetchCachedFirst(url) {
return fetch(url, { cache: 'force-cache' });
}
The cache option in fetch controls how the browser uses its HTTP cache.
This is different from the server's Cache-Control header.
Cache Busting
When using long max-age, include a hash in the filename (e.g., app.abc123.js).
When the file changes, the hash changes, creating a new URL that bypasses the old cache.
Build tools like Vite and webpack do this automatically.
← Back to HTTP Examples