Cache-Control Headers: How Browsers Decide What to Reuse
Every time a browser loads a page, it must decide whether to reuse a copy it already has or to fetch a fresh one. That decision is governed largely by the Cache-Control header, a short line of directives sent with a response. Get it right and repeat visits feel fast, because the browser reuses what it already downloaded. Get it wrong and visitors either see stale content for days or re-download everything on every visit. The Cache-Control Checker parses a Cache-Control header that you paste in and flags conflicts between its directives. It works on the text you supply, so it cannot see your live server configuration; it can only tell you whether the header you pasted says what you think it says.
How it works
The most important directive is max-age, which states, in seconds, how long a response may be reused before it is considered stale. Seconds are the unit, and that is a frequent source of error: a value of 3600 means one hour, because 3600 divided by 60 equals 60 minutes, and 60 minutes equals one hour. A value of 86400 means one day, because 86400 divided by 3600 equals 24 hours. Other directives shape who may cache and how revalidation works. The public directive says any cache may store the response, while private says only the visitor's own browser may store it, which matters for personalised pages. The no-store directive says the response must not be stored at all, and no-cache is widely misunderstood: it does not mean do not store, it means store but revalidate with the server before reuse.
Where it goes wrong
Conflicts are the checker's main quarry, and they are more common than they should be. A header that says both no-store and max-age=86400 contradicts itself, because one directive forbids storage while the other grants a day of reuse. A header that says both public and private is similarly confused about who may cache. Another conflict is subtler: must-revalidate combined with a long max-age is not a contradiction, but it changes behaviour once the response goes stale, forcing revalidation instead of allowing a stale copy to be served. The checker can surface these combinations, but only you can decide which directive reflects your intent, because the header cannot know whether a page is personal, public, or sensitive.
Worked example
Worked example with sample values. Suppose you paste this sample header: public, max-age=86400, must-revalidate. The checker can parse three directives: public, max-age=86400 and must-revalidate, and 1 plus 1 plus 1 equals 3. Converting the lifetime gives 86400 divided by 3600 equals 24, so the response may be reused for 24 hours. After 24 hours it becomes stale, and must-revalidate means the cache must check with the server before using it again, rather than serving the stale copy. If the sample instead read no-store, max-age=86400, the same conversion would still give 24 hours, but the two directives would conflict, and the safe reading is that the response should not be stored. The sample header here is illustrative, not copied from a live response.
Mistakes to avoid
Choosing lifetimes is a judgement call, not a formula. Files that never change, such as images with versioned file names, can carry long lifetimes, because a new version gets a new file name and the old cached copy is simply never requested again. HTML pages that change often should carry short lifetimes or revalidation, because serving a day-old homepage to a returning visitor is usually worse than a slightly slower fresh fetch. Personalised pages, account pages and anything containing private data should use private or no-store as appropriate, and caching rules should never be used as a substitute for proper access control. A cached copy of a private page in a shared cache is a privacy problem, not a performance win.
Putting it into practice
Use the checker while drafting or reviewing headers, before they reach a live server. Paste the exact header, read each directive in plain language, and resolve any conflict by removing the directive that does not match your intent. Keep a note of which lifetimes apply to which kinds of content, so that a future change to one content type does not accidentally apply to another. And remember that the checker reads text: after changing a live configuration, confirm the served header with a separate live check, since a configuration file and a served header are not always the same thing.
Related tools and reading: the DNS Lookup and the URL Encoder & Decoder cover neighbouring checks that pair naturally with this one, and the guide at [/blog/browser-cache-policy-builder-guide/] extends the same topic with further background and examples for readers who want to go deeper.
Key points
- max-age converted correctly: seconds, not minutes
- No direct conflict such as no-store with max-age
- public versus private matches whether content is personal
- Long lifetimes only for versioned, unchanging files
- Served header confirmed separately after live changes
In short: Cache-Control tells caches how long a response may be reused. The checker parses a pasted header and flags conflicting directives. max-age is measured in seconds, not minutes or hours. A conflicting header is a drafting error, not a speed guarantee.
One habit ties all of this together: re-check after every change. A result from the Cache-Control Checker is only as current as the text it was run on, so a fix, a redesign, or a new version of the underlying material deserves a fresh run rather than reliance on an old report. Keep the previous result alongside the new one, note what changed between them, and treat any new finding as a question to investigate rather than a verdict to accept or dismiss. That loop of checking, fixing, re-checking and recording is what turns a one-off test into a reliable routine, and it costs far less time than debugging a problem that a second check would have caught early.