Cache-Control Builder
Build a Cache-Control header for your resource type.
The Cache-Control header is the single most important HTTP header for deciding how long and under what conditions browsers and CDNs may cache a response. Get it wrong and users see stale content, or caching never kicks in and your server and bandwidth costs spike. This tool lets you pick a resource type and toggle directives, then assembles the correct Cache-Control string in real time.
Common scenarios such as hashed static assets, HTML documents, sensitive API responses and images are one click away via presets, and you can fine-tune max-age, s-maxage andstale-while-revalidate values directly. Everything runs in your browser; no input is ever sent anywhere.
Cache-Control: public, max-age=31536000, immutable
What the main directives mean
Cache-Control is a comma-separated list of directives. The most common ones are:
- public / private:
publicallows shared caches (like CDNs) to store the response;privaterestricts storage to the end user's browser only (for per-user responses). - max-age=N: how many seconds the response is considered fresh. During that window no request goes back to the server.
- s-maxage=N: freshness that applies only to shared caches (CDNs); it overrides
max-agethere. - no-cache: the response may be cached, but it must be revalidated with the server (a 304 check) before reuse.
- no-store: do not store the response in any cache. Use it for sensitive data.
- must-revalidate: once stale, the cache must revalidate and may not serve the old response while offline.
- immutable: while fresh, the browser sends no revalidation request even on a manual reload.
- stale-while-revalidate=N: for N seconds after expiry, serve the stale response immediately while refreshing in the background.
Hashed files get immutable + one-year caching
When a build tool fingerprints filenames with a content hash (e.g. app.4f3a9c.js), the filename itself changes whenever the contents change. Because a given URL's contents never change, it is safe to cache it for as long as possible. The recommended value ispublic, max-age=31536000, immutable (one year). Adding immutable means the browser skips conditional requests even on reload, eliminating the round trip entirely.
- Unhashed HTML entry point: use
no-cacheso users always get the latest version. - Hashed JS/CSS/fonts:
public, max-age=31536000, immutable. - Images/media: if they rarely change, start around
public, max-age=86400(one day). - Personalized or sensitive responses:
no-store, private.
Common conflicts and gotchas
no-store forbids caching entirely, so combining it with max-age orimmutable is contradictory. This tool flags such combinations with a warning. Also remember thatno-cachedoes not mean "do not cache"; it means "revalidate every time." To fully prevent caching, use no-store. To tune the stale-while-revalidate window to how often your data changes, the stale-while-revalidate planner helps.
Recommended Cache-Control by resource type
Here are copy-ready combinations grouped by resource type. All max-age values are in seconds.
| Resource type | Recommended value | Why |
|---|---|---|
| Hashed JS/CSS/fonts | public, max-age=31536000, immutable | URL changes on content change, so permanent caching is safe |
| HTML entry point | no-cache | New deploys show instantly, while ETag still saves bytes via 304 |
| Rarely changing images | public, max-age=86400, stale-while-revalidate=604800 | Fresh for a day; serve stale instantly for a week while refreshing |
| Public API (JSON) | public, max-age=0, s-maxage=60 | Browser checks every time; only the CDN caches for 60s |
| Logged-in user response | private, no-cache | No CDN storage; browser revalidates before reuse |
| Passwords, payments, tokens | no-store | Stored nowhere, including the back/forward cache |
Worked example: reading a public API response
Suppose a response carries Cache-Control: public, max-age=0, s-maxage=60, stale-while-revalidate=30. The behavior splits in two. The browser (a private cache) sees max-age=0, treats the response as stale on every request, and sends a conditional request each time. The CDN (a shared cache), however, appliess-maxage=60, which overrides max-age there, so for 60 seconds it answers without touching the origin. After those 60 seconds, stale-while-revalidate=30 lets the CDN return the stale copy instantly for another 30 seconds while it refreshes in the background. The net effect: the origin is hit at most once per 60 seconds, staying stable even under a traffic spike.
Common pitfall
- max-age=0 is not no-store:
max-age=0means "immediately stale, but storage is still allowed (reuse after revalidation)." To prevent caching at all, you must useno-store. - private + s-maxage is meaningless:
s-maxagetargets shared caches only, butprivatealready forbids shared-cache storage, sos-maxageis simply ignored when both are present.
Frequently asked questions
What is the difference between no-cache and no-store?
What unit is max-age?
Does immutable mean my updates won't show after a deploy?
What happens if I set both s-maxage and max-age?
Is my input sent to a server?
Related guides
- Cache-Control Done Right: Making Browser Caching WorkWhat max-age, no-cache, no-store and immutable really mean, with recommended policies per resource type.