To answer the question, there are two players here, the client (request) and the server (response).
Client:
The client can only request with ONE cache method. There are different methods and if not specified, will use default
.
- default: Inspect browser cache:
- If cached and "fresh": Return from cache.
- If cached, stale, but still "valid": Return from cache, and schedule a fetch to update cache (for next use).
- If cached and stale: Fetch with conditions, cache, and return.
- If not cached: Fetch, cache, and return.
- no-store: Fetch and return.
- reload: Fetch, cache, and return. (default-4)
- no-cache: Inspect browser cache:
- If cached: Fetch with conditions, cache, and return. (default-3)
- If not cached: Fetch, cache, and return. (default-4)
- force-cache: Inspect browser cache:
- If cached: Return it regardless if stale.
- If not cache: Fetch, cache, and return. (default-4)
- only-if-cached: Inspect browser cache:
- If cached: Return it regardless if stale.
- If not cached: Throw network error.
Notes:
- Still "valid" means the current
age
is within the stale-while-revalidate
lifetime. It needs "revalidation", but is still acceptable to return.
- "Fetch" here, for simplicity, is short for "non-conditional network
fetch".
- "Fetch with conditions" means fetch using headers like
If-Modified-Since
, or ETag
so the server can respond with 304: (Not Modified)
.
https://fetch.spec.whatwg.org/#concept-request-cache-mode
Server::
Now that we understand what the client can do, the server responses make more sense.
Looking at the Cache-Control
header, if the server returns:
- no-store: Tells client to not use cache at all
- no-cache: Tells client it should do conditional requests and ignore freshness
- max-age: Tells client how long a cache is "fresh"
- stale-while-revalidate: Tells client how long cache is "valid"
- immutable: Cache forever
Now we can put it all together. That means the only possibilities are:
- Non-conditional network fetch
- Conditional network fetch
- Return stale cache
- Return stale but valid cache
- Return fresh cache
- Return any cache
Any combination of client, or server can dictate what method, or set of methods, to use. If the server returns no-store
, it's not going to hit the cache, no matter what the client request type. If the client request was no-store
, it doesn't matter what the server returns, it won't cache. If the client doesn't specify a request type, the server will dictate it with Cache-Control
.
It makes no sense for a server to return both no-cache
and no-store
since no-store
overrides everything. Yes, you've probably seen both together, and it's useless outside of broken browser implementations. Still, no-store
has been part of spec since 1999: https://datatracker.ietf.org/doc/html/rfc2616#section-14.9.2
In real life usage, if your server supports 304: Not Modified
, and you want to use client cache as a way to improve speed, but still want to force a network fetch, use no-cache
. If don't support 304
, and want to force a network fetch, use no-store
. If you're okay with cache sometimes, use freshness and revalidation headers.
In reality, if you're mixing up no-cache
and no-store
on the client, very little would change. Then, just a couple of headers get sent and there will different internal responses handled by the browser. An issue can occur if you use no-cache
and then forget to use it later. no-cache
tells it to store the response in the cache, and a later request without it might trigger internal cache.
There are times when you may want to mix methods even on the same resource based on context. For example, you may want to use reload
on a service worker and background sync, but use default
for the web page itself. This is where you can manipulate the user agent (browser) cache to your liking. Just remember that the server generally has the final say as to how the cache should work.
To clarify some possible future confusion. The client can use the Cache-Control
header on the request, to tell the server to not use its own cache system when responding. This is unrelated to the browser/server dynamic, and more about the server/database dynamic.
Also no-store
technically means must not store to any non-volatile storage (disk) and release it from volatile storage (memory) ASAP. In practice, it means don't use a cache at all. The command actually goes both ways. A client request with no-store
shouldn't write to disk or database and is meant to transient.
TL;DR: no-store
overrides no-cache
. Setting both is useless, unless we are talking out-of-spec or HTTP/1.0 browsers that don't support no-store
(Maybe IE11?). Use no-cache
for 304
support.
no-cache
does not mean what you think it does. Actually, it means "please revalidate". – Ophthalmia