You push a CSS fix. Your teammate refreshes and still sees the old button. Someone says "hard refresh," someone else says "it's the CDN," and you spend twenty minutes reading the same MDN page you read last quarter.
HTTP caching is one of those topics most of us have "learned" four or five times. Each time it makes sense for about a week. Then no-cache and no-store swap places in your head again, and you're back to guessing.
I don't think the headers are that hard. The trouble is how we pick them up: under pressure, mid-bug, from a Stack Overflow answer that fixed one thing. Here's how I finally got them to stay.
Start with the two questions every cache asks
Every cache, whether it's the browser, a CDN, or a reverse proxy, asks two things about a response.
- Can I store this at all?
- If I have a copy, can I use it without asking the server?
Almost every header you'll meet answers one of those. Once I sorted them into those two buckets, the list stopped feeling random.
Can I store it? Cache-Control: no-store says no, never write it down. private says only the user's browser may keep it, not a shared CDN. public says shared caches are fine too.
Can I reuse it without asking? That's freshness. max-age=3600 means the copy is fresh for an hour. s-maxage is the same idea for shared caches only. Expires is the older way of saying it with a date, and if max-age is present, it wins.
Then there's the one everybody gets wrong. no-cache doesn't mean "don't cache." It means "you can store it, but check with the server before every reuse." I had that backwards for an embarrassingly long time.
Revalidation is where ETag comes in
When a stored copy goes stale, the cache doesn't have to download everything again. It can ask, "has this changed?"
That's what validators are for. The server sends an ETag (a fingerprint of the content) or a Last-Modified date. Later, the browser sends If-None-Match with the ETag, or If-Modified-Since with the date. If nothing changed, the server replies 304 Not Modified with no body, and the cache keeps using its copy.
So no-cache plus an ETag is a perfectly reasonable setup for HTML. You always check, but checking is cheap.
The one pattern worth memorizing
If you only keep one thing, keep this:
- Hashed static files (
app.3f9a1c.js,styles.8b2e.css):Cache-Control: public, max-age=31536000, immutable. The filename changes when the content does, so the old URL can live forever. - HTML:
Cache-Control: no-cache, with an ETag. The page always checks in, so it picks up the new asset filenames right after a deploy. - Anything with private user data:
private, orno-storeif it really shouldn't touch disk.
That split explains most "why is the old CSS still there?" bugs. Usually someone gave the HTML a long max-age, or shipped assets without a hash in the name.
Why it keeps falling out of your head
Here's my honest read on the forgetting part. We learn caching reactively. A bug shows up, we fix it, the fix works, and we never look at the reasoning again. Nothing pulls it back up until the next bug, months later.
Re-reading the docs feels productive and doesn't help much. What works better is trying to answer from memory first, getting it wrong, then checking. That's retrieval practice, and spaced out over a few weeks, it's the difference between "I've read about ETags" and "I know when I'd use one."
So when I finally fixed a caching bug properly, I saved the MDN page and the talk that explained it into Recl. It turns a link or video into a short summary with key takeaways, files it under a topic, and then brings it back later as a quick recall question.
The useful part was writing my own note on the save. Something like: "no-cache = store but always revalidate. no-store = never store. HTML gets no-cache, hashed assets get immutable." That note is what I actually need when I'm staring at response headers in DevTools.
Let the reminders do the remembering
A few days later, a nudge shows up: "Still remember this one?" The question is something like what no-cache actually does. If I get it right, it comes back in a week. If I blank, I read my note and it comes back sooner.
You can do the same thing with plain flashcards. The tool matters less than the habit of being asked before you need the answer. I just find it easier when the cards come from things I already saved, instead of a separate deck I have to build and maintain.
A short loop you can run this week
- Open DevTools on a site you work on. In the Network tab, look at the
Cache-ControlandETagheaders on your HTML and on one JS file. - For each, say out loud which of the two questions it answers: can I store it, or can I reuse it without asking?
- Write the HTML-versus-hashed-assets rule in your own words somewhere you'll see it again.
- Next week, before checking, try to explain
no-cacheversusno-storeto yourself. Then check.
It's a small topic. You don't need to memorize RFC 9111. You need three or four rules that are still there the next time a deploy looks stale, and a way to keep them from fading between bugs.
If you want to see what summarized takeaways look like on real material, the public Recl library has a few hundred of them.
I'm Asutosh, and I build Recl, an app for saving videos, articles and notes, getting the key ideas, and recalling them on a schedule so they actually stick.


