You share a post at night and delete it in the morning. The app confirms it is gone. Then a friend messages: "I can still see it." Nothing is broken. The post really was deleted from the database. It is still visible because the database was never the only place it lived.
One post, many copies
Fetching every post straight from the database for every viewer would be slow and expensive, so popular systems keep copies closer to the people looking at them:
- CDN edge caches. A content delivery network keeps copies on servers around the world, so a viewer in Pune gets the post from a nearby server instead of the origin.
- The app or browser cache. Feed apps fetch the next few posts before you scroll to them, so scrolling never stops to load. Those posts are already on the phone.
Deleting the row in the database stops new copies from being made. It does not reach out and wipe the copies that already exist.
Picture a hostel during exams. The date sheet is on the main notice board, copies are pinned on every floor's board, and some students have photos of it on their phones. When the warden takes the main sheet down, the floor copies and the photos are still there. The main board is the database, the floor boards are the CDN, and the photos are the app cache. Getting rid of those copies is called cache invalidation.
Fix 1: purge
A purge (CloudFront calls it an invalidation) tells the CDN to drop its copy, so the next request goes back to the origin and finds nothing. It is fast: Fastly and Cloudflare each publish an average global purge time of about 150 ms for their own networks. But it has two limits.
- It does not reach phones or browsers. AWS says it plainly: after an invalidation, "the user might continue to see the old version until it expires from those caches."
- One post is many URLs. The post, its thumbnail, resized images and its API response are all cached separately. Purge one URL and the others stay live. That is why CDNs support purging by tag (a Cache-Tag or surrogate key shared by every URL of a post).
Fix 2: a short TTL
Every cached copy can carry an expiry. With Cache-Control: max-age=300, caches may reuse the copy for five minutes without asking the server, then must fetch it again. After a delete, every copy disappears within five minutes, including the ones on phones, which a purge cannot reach. The cost is that window: the post can stay visible for up to the TTL. Shorter TTLs shrink the window but send more requests to the origin.
The notice board stops matching the real thing here: a paper notice has no expiry stamp that works by itself, and photos in a gallery never expire. Caches do expire, which is what makes TTL possible.
Use both
Purge what you control, the CDN, the moment something is deleted, by tag so every URL of the post goes together. Keep a short TTL on user content as the safety net for the copies you cannot reach. For files that only ever change, such as scripts and stylesheets, use versioned file names with a long TTL instead.
The database forgets instantly. The copies forget on their own schedule.
Headers worth knowing
max-age=N: fresh for N seconds; reused without asking the server.no-cache: may be stored, but must be checked with the server before every reuse. It does not mean "don't cache".no-store: never stored anywhere. Deletes show at once, but every request hits the origin.s-maxage: a max-age for shared caches such as a CDN only; browsers ignore it.
Sources: MDN, Cache-Control; AWS CloudFront, Invalidation; Cloudflare, Instant Purge; Fastly, Instant Purge.