OneWebDesk

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.

Presets
Directives
Cache-Control header
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: public allows 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 overridesmax-age there.
  • 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.

  1. Unhashed HTML entry point: use no-cache so users always get the latest version.
  2. Hashed JS/CSS/fonts: public, max-age=31536000, immutable.
  3. Images/media: if they rarely change, start around public, max-age=86400 (one day).
  4. 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 typeRecommended valueWhy
Hashed JS/CSS/fontspublic, max-age=31536000, immutableURL changes on content change, so permanent caching is safe
HTML entry pointno-cacheNew deploys show instantly, while ETag still saves bytes via 304
Rarely changing imagespublic, max-age=86400, stale-while-revalidate=604800Fresh for a day; serve stale instantly for a week while refreshing
Public API (JSON)public, max-age=0, s-maxage=60Browser checks every time; only the CDN caches for 60s
Logged-in user responseprivate, no-cacheNo CDN storage; browser revalidates before reuse
Passwords, payments, tokensno-storeStored 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-maxage targets shared caches only, butprivate already forbids shared-cache storage, so s-maxage is simply ignored when both are present.

Frequently asked questions

What is the difference between no-cache and no-store?
no-cache stores the response but revalidates with the server (usually a 304 check via ETag) before every reuse. no-store never stores it in any form. When you truly want to prevent caching, use no-store.
What unit is max-age?
Seconds. One hour is 3600, one day is 86400, and one year is 31536000 seconds. The presets in this tool use these values.
Does immutable mean my updates won't show after a deploy?
immutable is a promise that the contents at a given URL never change. That is why you must fingerprint filenames with a content hash so the URL changes on every deploy. Using immutable without hashing risks serving the old version for up to max-age.
What happens if I set both s-maxage and max-age?
Shared caches like CDNs honor s-maxage, while private caches like browsers follow max-age. Use both together when you want a long cache at the CDN but a short cache in the browser.
Is my input sent to a server?
No. The header string is assembled entirely in your browser and no data is sent anywhere.

Related guides

Related tools