Stale or Fresh: Caching Basics
The city's map on Vera's second screen says Old Market has nine bikes. She asks the API directly, at the same moment, and it says seven. Neither is lying and nothing is broken. The map's number is a minute and a half old, because somewhere between the server and that screen a saved copy was handed over instead of a fresh trip being made.
That saving-and-reusing is caching, and it is most of the reason the internet feels fast. The question this page installs, permanently, is not "is this number right?" but the more useful one: how old is this answer?
Why Copies Get Served
Going all the way to the source costs something every time: the server has to look the answer up, and the answer has to travel. When thousands of clients ask the same popular question in the same minute — how many bikes are at Old Market — answering each one from scratch is enormous effort for an identical result.
So the answer gets kept. A cache is simply a place along the way that stores a recent response and hands it out again to the next asker. There are several such places: the server's own layer in front of itself, networks in between, the browser on your machine. None of them asked your permission, and none of them needs to; the trade is freshness for speed, made on purpose.
The everyday version is the departure board at a station. It refreshes every minute and is almost always right enough to act on. You could instead walk to the platform and ask a member of staff for every single glance, and you would be marginally more current and thoroughly exhausted — and if everyone did it, the staff would stop being able to do anything else. Boards exist because "right enough, instantly" beats "perfect, eventually" nearly every time.
The Honesty Headers
Caching is not something happening behind your back. It is narrated in the response headers, on the same -i output you have been reading since Chapter 3.
HTTP/1.1 200 OK
Cache-Control: max-age=120
Age: 90
Content-Type: application/json
{"id": "st_014", "name": "Old Market", "capacity": 24, "free_bikes": 9}
Two headers tell the whole story. Cache-Control carries the server's own declaration of shelf life: max-age=120 means a copy of this answer may stand for two minutes. Age is the copy's confession: this one has been sitting for ninety seconds already. Ninety against a hundred and twenty means the answer is genuine, permitted, and half a minute from expiry — and the nine bikes it reports were true a minute and a half ago.
There is a third piece worth recognizing when you meet it. Servers often attach an ETag, a short fingerprint of the answer they sent. Send that fingerprint back on your next request — in a header called If-None-Match — and you are asking a cheaper question: "has this changed since the version I hold?" If it has not, the server replies 304 Not Modified with no body at all — a yes-you-are-current that costs almost nothing to send or receive. You will see it far more often than you will type it.
Reading Data with a Clock in Mind
Different questions tolerate different ages, and matching the two is the real skill on this page. The bikes at a station change minute by minute, and a two-minute-old count is fine for deciding whether to walk over. The Thursday report describes a week, and an hour-old snapshot changes none of its conclusions. A payment confirmation tolerates nothing at all: it is either done or it is not.
So before fetching anything, answer one question: how old may this answer be? The answer is almost never "zero seconds", and once you have said it out loud, the fetching pattern follows on its own — every ten seconds, once an hour, or once, on Thursday morning.
When You Truly Need Now
Sometimes the answer really is "as fresh as possible". You can go past your own saved copies: a hard refresh in the browser ignores what it had stored, and a fresh curl skips anything your own machine kept — though a shared cache further down the road may still be the thing that answers, which is exactly what an Age header confesses. What you cannot do is order the world to forget — a server's max-age is also its load management, and the layers between you honor it.
That is worth taking as a courtesy rather than an obstacle. Bypassing caches to poll a two-minute-fresh number every second is the rush-hour mistake from the previous topic, in a quieter setting: it burns the request budget, produces no information anybody can act on, and the freshness it buys is smaller than the gap between the reading and the decision it feeds.
- "Two different numbers means the API is broken." It means two answers of different ages, which is normal and declared. Check
Ageagainstmax-agebefore filing a bug that is not one, and note that the app and the API disagreeing is a symptom with a boring explanation. - "Caching happens invisibly, so I cannot see it." It is announced in headers on every response, and browsers mark the rows in their network panel that were served from a stored copy rather than fetched. It is one of the best-narrated mechanisms in HTTP.
- "Always force a fresh answer, just to be safe." Fresh costs requests, and requests are counted. It is only safer when the extra seconds of accuracy would actually change what you do, and for most questions they would not.
- "A cache is a thing I install." There are caches you can control, but the ones in this chapter are already there: in the browser, in the network, in front of the server. Your part is reading what they say about themselves.
- A whole family of "the app and the API disagree" mysteries collapses into one header glance. Staleness explains most of them, and being able to say so in ten seconds saves an afternoon and an unnecessary support email.
- Freshness-matching is the third leg of designing under the ceiling. Space the requests, ask narrower questions, and stop re-asking what has not changed: this chapter's last three pages are one budget seen from three sides.
Knowledge Check
A response carries Cache-Control: max-age=120 and Age: 90. What does that mean?
- Ninety of a hundred and twenty allowed requests are spent
- Your request waited ninety seconds in a queue of a hundred
- A copy may live two minutes and this one is ninety seconds old
- The server is ninety seconds behind on a backlog of two minutes
Why do caches exist between you and the server?
- Repeating a recent answer is far cheaper than fetching it again
- They keep the contents of responses private while in transit
- They check each answer for correctness before it reaches you
- They enforce the sixty-per-minute limit on the caller's behalf
The city map shows nine bikes at Old Market and a direct request says seven. What is the most likely explanation?
- The map is calling a different endpoint than the one you called
- The map is showing a stored copy from a couple of minutes ago
- The server is malfunctioning and returning two different totals
- The map counts docked bikes and the API counts every bike
Vera needs station counts for a report describing the whole week. How fresh must her data be?
- Freshest possible, so she should re-fetch every few seconds
- An hour-old snapshot is fine for a question about a week
- She should force past every cache on each of the five pages
- Freshness cannot be judged, so the headers are best ignored
You got correct