HTTP caching reduces latency, saves bandwidth, and improves user experience by storing copies of resources. This tutorial covers the core mechanisms, headers, and practical implementation tips.
The Cache-Control header instructs caches how to store and reuse responses. Common directives:
Cache-Control: public, max-age=86400, stale-while-revalidate=3600
An ETag is a validator representing a specific version of a resource. Clients send If-None-Match to check if the resource changed.
ETag: "b5b8e3c71a8e0c2"
If-None-Match: "b5b8e3c71a8e0c2"
If unchanged, the server replies with 304 Not Modified, saving bandwidth.
Older but still supported, Last-Modified provides the timestamp of the resource's last change.
Last-Modified: Wed, 21 Oct 2020 07:28:00 GMT
If-Modified-Since: Wed, 21 Oct 2020 07:28:00 GMT
Both browsers and intermediate proxies honor caching headers. Service Workers can implement custom cache logic for offline support.
Node.js/Express snippet serving a static asset with strong caching:
const express = require('express');
const app = express();
app.use(express.static('public', {
setHeaders: (res, path) => {
if (path.endsWith('.css') || path.endsWith('.js')) {
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
} else {
res.setHeader('Cache-Control', 'public, max-age=3600, stale-while-revalidate=86400');
}
}
}));
app.listen(3000, () => console.log('Server running on :3000'));
/css/app.v1.2.3.css) for long‑term caching.Cache-Control: no-store for sensitive data.ETag with Cache-Control for optimal freshness.curl -I and Chrome DevTools Network panel.