Cache-Control no-cache vs no-store, what Chrome actually does (tested)
no-cache means 'cache it, but ask first'; no-store means 'don't keep it'. We measured what Chrome sent to the server for each common value when the page was opened again.
1. What reached the server on the second visit
| Cache-Control on the file | Revisit / reload |
|---|---|
no-cache | Request with If-None-Match → 304, no body |
max-age=0 | Same as no-cache: 304 |
max-age=0, must-revalidate | Same: 304 |
no-store | Full 200 download again, no conditional request |
no-cache, no-store, must-revalidate | Full 200 again (no-store wins) |
max-age=60 / private, max-age=60 | No request at all (served from cache, even on reload) |
| (no Cache-Control, only ETag + Last-Modified) | No request at all |
2. What that means
- no-cache keeps a copy and checks it every time. With an ETag or Last-Modified the check is a small 304, so it's the right choice for HTML and API responses that must always be current.
- no-store keeps nothing: every visit downloads the whole response. Use it for private data (account pages, banking, tokens), not for speed.
no-cache, no-store, must-revalidate, the popular "disable caching" line, behaved exactly likeno-storealone.- No header is not "not cached". With only a Last-Modified two hours old, Chrome reused the file without asking (heuristic caching, a fraction of the file's age). If a file must update immediately, send
no-cacheexplicitly. - Reload didn't re-request a script with
max-age=60: modern Chrome only revalidates the page itself on a normal reload. To bust long-lived files, change their URL (app.3f9c1.js).
3. A sensible setup
# HTML: always current, cheap 304s
location / {
add_header Cache-Control "no-cache" always;
}
# fingerprinted assets: cache for a year
location /assets/ {
add_header Cache-Control "public, max-age=31536000, immutable" always;
}
# private pages
location /account/ {
add_header Cache-Control "no-store" always;
}
private only tells shared caches (CDNs, proxies) not to store it; the browser still cached it in our test. ETags make the no-cache 304s work: see how nginx builds them. Inspect a URL's headers with curl -sI or the free HTTP headers tool.
Frequently asked questions
What is the difference between no-cache and no-store?
no-cache stores the response but checks with the server before each use; in our Chrome test that was a 304 with no body. no-store keeps nothing, so every visit was a full 200 download.
Is max-age=0 the same as no-cache?
In our Chrome test, yes: both (with or without must-revalidate) revalidated and got a 304 on every revisit.
Does no-cache, no-store, must-revalidate make sense?
It works, but in our test it behaved exactly like no-store alone. Use no-store for private data, no-cache for content that must be fresh.
Is a response without Cache-Control cached?
Yes. A script with only ETag and a two-hour-old Last-Modified was reused by Chrome without any request.
Written with AI assistance. Measured on 2026-10-01 in Chromium 153 (full build, new headless, fresh profile per row): a page loaded a script whose response carried each Cache-Control value plus ETag "v1" and a Last-Modified two hours old; the page was then opened again (revisit) or reloaded, and the server logged every request for the script and whether it answered 304. CDN behaviour for 'private' and the nginx lines are from the HTTP spec and nginx docs, not this test. PlainHeaders is our extension; curl and the HTTP headers tool are free.