CDN edge caching and origin revalidation
This asks how a CDN decides what to cache at the edge instead of treating every request as an origin lookup. Read it to see how cache keys separate representations, how freshness and validation govern reuse, and why correctness still constrains the cacheable surface.
At 09:00, a release changes the banner image on a retail site. The object storage bucket contains the new file, the application emits the new URL in its page markup, and direct requests to the origin return the expected bytes. Yet some users continue to receive the previous banner while others receive the new one. The failure is not necessarily a failed deployment. Requests are terminating at geographically separate edge points, each holding entries created at different times and under different request variants. A cache is serving a valid response according to the policy it was given, but that policy no longer matches the deployment’s consistency expectation.
The inverse failure arrives during a traffic spike. A product endpoint is technically cacheable for a short interval, but the CDN has been configured to bypass its cache whenever a session cookie appears. Most browsers send that cookie even though the endpoint’s response is identical for all anonymous viewers. Each edge request therefore reaches the application, database reads rise, and the CDN becomes a routing layer rather than a load-shedding layer. What goes wrong before any cache algorithm enters the discussion is classification: the system has not established which requests denote the same response, nor how long a response remains safe to reuse.
A cache entry begins with an equivalence claim
An edge cache does not cache a URL in the abstract. It stores a response under a cache key, an identifier assembled from selected request properties. The method and normalized scheme, host, path, and query string commonly participate. Configuration may also include selected headers, cookies, device hints, geography, or an application-defined key. A hit means the edge believes the current request is equivalent, for caching purposes, to the request that produced the stored response. This is why cache-key design is a correctness boundary rather than a tuning detail: omitting a response-affecting input can return the wrong representation to a different requester.
The opposite error is safer but expensive. Including a high-cardinality cookie, an unbounded query parameter, or every request header splits one broadly reusable object into many entries. Hit ratio falls because request history is dispersed across keys, and eviction removes objects before they accumulate enough reuse. Headers named by Vary make this issue explicit at the HTTP layer. If the origin selects a representation based on Accept-Encoding, Accept-Language, or another field, that field must be reflected in cache selection. Adding Vary: Cookie indiscriminately usually declares that every cookie changes output, which is what breaks when cookies carry tracking or session state unrelated to the representation.
- Normalize request. derive the method, URL, and selected variation inputs
- Find entry. look up the representation under the resulting cache key
- Test policy. determine freshness, permissions, and request directives
- Serve or validate. return locally, make a conditional request, or fetch anew
- Store or bypass. admit a cacheable response and attach its metadata
Freshness is permission to reuse without contact
Once an entry exists, its age alone does not decide whether it can be served. The response’s cache directives and CDN policy establish a freshness lifetime. While current_age is below that lifetime, an edge can return the stored bytes without asking origin whether they changed. Cache-Control: max-age communicates a client-facing lifetime; s-maxage can assign a distinct shared-cache lifetime; Expires provides an older absolute-date form. CDNs often layer explicit rules over these headers, assigning defaults by path or status class, overriding origin directives, or preventing storage for sensitive routes. The effective policy is the result of those layers, not merely the header visible in a browser trace.
Freshness creates bounded staleness deliberately. If an object has s-maxage of ten minutes, the origin may change one second after the edge stores it, and that edge may continue to serve the prior representation for almost ten minutes. That leaves a product decision embedded in transport metadata: static assets with content-hashed filenames can safely have long lifetimes because changed content receives a new key, while a mutable JSON document may require a short lifetime or a different delivery pattern. A short TTL reduces the maximum unplanned delay, but it also moves more requests toward origin at expiry boundaries and makes cache performance more dependent on request timing.
Stale does not always mean download it again
When a stored entry is stale, the edge has several possible paths. It can fetch a complete replacement from origin. More efficiently, if the response carries a validator such as an ETag or Last-Modified timestamp, it can send If-None-Match or If-Modified-Since. Origin compares that validator with its current representation. A 304 Not Modified response tells the edge to retain the body, refresh its metadata, and serve the existing bytes; a changed validator produces a new representation. Conditional revalidation saves transfer volume and often serialization work, but it still consumes an origin request and requires the origin to evaluate the condition consistently.
This distinction matters under concentrated demand. Suppose many edge locations hold the same entry with a short TTL. When it expires, each location can independently revalidate, creating a distributed burst of conditional requests even if all receive 304. CDN request collapsing, also called coalescing, reduces the local version of this problem by allowing one in-flight origin fetch for a key while equivalent requests wait for its result. It cannot collapse across every edge location unless the provider’s architecture includes an intermediate shield or tier. Which is what breaks when freshness is used as the only invalidation mechanism for a popular object: the origin sees synchronization effects generated by the cache fleet.
Serving stale is a controlled failure mode
HTTP directives can authorize a cache to serve stale content under defined conditions. stale-while-revalidate permits a cache to return a stale response immediately while it refreshes it in the background. stale-if-error permits stale content when origin returns an error or cannot be reached. CDNs also expose related controls such as origin shielding, background refresh, and error-response caching. These features change the latency and availability profile: an edge can continue serving a recently valid representation during an origin incident instead of amplifying the incident with retries and timeout queues.
The trade is semantic, not merely operational. Serving stale CSS during an outage is often acceptable; serving stale account permissions, inventory availability, or signed download authorization may violate the application’s contract. Even for public data, a stale response can conceal a rollback, a legal removal, or an emergency correction. Therefore stale windows belong to data classes, not generic resilience settings. A route can have an acceptable fresh lifetime, a different acceptable stale-while-revalidate interval, and no acceptable stale-if-error interval. Conflating those choices produces policies that appear reliable in aggregate while failing the one representation whose recency requirement is strict.
Origin return is also triggered by request semantics
A cacheable GET is not automatically reusable when the request contains directives that constrain reuse. Cache-Control: no-cache means a stored response may exist, but it must be successfully validated before being used. no-store prohibits storing the response and generally signals that retaining it is unsafe. Authorization, Set-Cookie, private, and response-specific policy can prevent shared caching unless explicitly configured otherwise. Methods also matter: GET and HEAD have conventional cache semantics, whereas POST, PUT, PATCH, and DELETE generally reach origin because they mutate state or because response reuse has not been defined for them.
Application behavior can create less visible origin trips. A CDN may bypass caching when query strings are present, when an origin response lacks explicit cacheability metadata, when the object exceeds a size threshold, or when a configured rule identifies a request as personalized. Redirects and error responses may be cached under separate rules, so an accidental cacheable redirect can persist after the routing error has been fixed. Range requests can be served from a complete stored object or require origin depending on cache capabilities and object state. The practical question is not simply whether a response has a Cache-Control header; it is whether every layer agrees that this particular request, response, and variation dimension is safe to retain.
| Dimension | Long-lived reusable object | Frequently validated mutable object |
|---|---|---|
| Identity | Content-addressed URL or tightly bounded variants | Stable URL whose representation changes in place |
| Edge behavior | Serve locally for most requests | Reach freshness boundary and revalidate repeatedly |
| Release path | Publish a new URL, retain old object safely | Overwrite origin object, purge or await expiry |
| Failure mode | Storage and eviction pressure | Stale reads or concentrated origin validation |
Invalidation changes state before expiry
A purge, invalidation, or cache-tag operation tells the CDN to remove or mark entries unusable before their natural freshness lifetime ends. It is the operational answer to mutable URLs that cannot wait for TTL expiry. A precise purge targets one URL and, depending on platform semantics, its variants. Tag-based invalidation groups many objects under an application-defined surrogate key, allowing a content update to invalidate pages, fragments, and API responses that depend on the same entity. Wildcard purges are broader and can clear a path family, but broad scope replaces a predictable cache hit rate with a temporary origin-load event.
Invalidation is not a transactional broadcast coupled to the origin write. Propagation takes time, entries may have different variants or regional copies, and requests already in flight can still complete with the prior response. A safe publication sequence therefore depends on compatibility between old and new representations. Content-addressed static assets avoid most of the issue because old and new objects coexist under distinct keys. For mutable routes, origin must be prepared to serve the new state before purge propagation begins, and the application must tolerate a bounded period in which edges differ. This is why purge is best understood as convergence control, not a guarantee that no stale byte can be observed after an update.
The unresolved boundary is cacheability of personalized state
The hard cases are not images or immutable bundles; they are responses that mix shared and user-specific data. An HTML document may contain mostly common layout plus a cart count, experiment assignment, locale, entitlement, or regional price. Caching the whole document on a key that ignores those fields leaks or misstates state. Including all of them destroys reuse. Fragment caching, edge-side includes, client-side hydration, signed variation tokens, and carefully normalized cookies each move the boundary, but none removes the underlying choice about which parts of a representation are shared and which must be computed per requester.
Reasonable engineers still disagree about where that boundary belongs. Longer TTLs with aggressive purging favor origin protection and low edge latency but accept propagation complexity and occasional stale reads. Short TTLs with revalidation favor simpler update semantics but can create origin dependence precisely during demand spikes. Rich cache keys preserve correctness for variation-heavy applications but reduce reuse and complicate observability; normalized keys increase hit ratio but demand a stronger proof that excluded inputs cannot affect output. The CDN can make these trade-offs explicit through keys, directives, validators, and invalidation, but it cannot determine the application’s consistency contract on its own.
Reading focus
Cache-key construction with representation ambiguity as its limit
Freshness lifetimes with invalidation delay as its limit
Origin revalidation with origin capacity and consistency as its limit