CDN and HTTP Caching Layers
LESSON
CDN and HTTP Caching Layers
By the end of this lesson, you will be able to...
Trace a reusable response from the browser through an edge cache, the origin, and an application cache.
Classify a response by audience, change pattern, and freshness need before choosing where it may be reused.
Defend a cache-boundary choice without treating a CDN, HTTP headers, or Redis as interchangeable tools.
Idea in one sentence: The most valuable cache hit is often one that prevents a request from reaching the origin, but only content that is safe for that audience and freshness promise may take that shortcut.
Core Insight
The course platform has a popular public landing page. At 09:00 a new cohort opens registration and thousands of people load it within minutes. The page includes a versioned JavaScript bundle, a course image, a public catalogue summary, and, for signed-in learners, a small “your enrolled courses” panel.
The origin is healthy, and lesson 002 has already put public course details in a shared Redis cache. Yet the origin is still doing avoidable work: receiving requests for the same bundle, sending the same image across continents, and assembling the same public catalogue response over and over.
That pressure exposes a different cache question:
At which point in the request path may this particular representation be reused?
Redis answers a question behind the application: can several API instances reuse one temporary value? Browser and edge caching answer a question before the application: can the client or an intermediary reuse a response without contacting the origin at all?
The request path makes the distinction concrete:
browser cache -> CDN edge -> origin/API -> shared Redis cache -> database
Every layer may decline to serve. A browser might lack a copy. An edge location might have no suitable entry. The origin may then call Redis, which may miss, and the database remains the source of truth. The design is not “put a cache everywhere”; it is deciding which copies are allowed, for whom, and under what promise.
The Promise We Need to Keep
For the landing page, the product can make several different promises:
- A deployed JavaScript bundle must match the version named in its URL.
- A public course image may be a few hours old if an editor replaces it, provided the replacement process has a clear path to reach users.
- The public catalogue may show a recently changed description briefly, but should not make a learner wait on the origin for every view.
- The personal enrollment panel must never show one learner's information to another learner.
- Enrollment, pricing at checkout, and authorization decisions must use their own authoritative rules; a fast public page must not decide them.
Notice that “the landing page” is not one cache class. It is a composition of representations with different audiences and different consequences when old. A good cache policy is therefore attached to a response or fragment boundary, not to a vague label such as “frontend data.”
Three plain questions produce the first design:
- Who may reuse it? One browser, any anonymous visitor, or only the origin?
- How does it change? Is it versioned and immutable, slowly edited, or a live personal decision?
- What may a reader believe while it is old? That answer is its freshness budget.
The HTTP terms are useful, but they should follow the questions:
- cacheability: who is permitted to reuse the representation;
- freshness: how long it may be used without checking again;
- validation: a cheaper way to ask whether an existing copy still matches the origin.
Headers such as Cache-Control and validators such as ETag carry those choices through the request path. This lesson uses them as policy signals, not as a catalog of protocol directives; the companion HTTP track goes deeper into directive and proxy semantics.
The Naive Design: Make the CDN Cache Everything
A tempting response to the 09:00 surge is: “The CDN is in front of us, so cache the whole page for everyone.” It seems efficient. A nearby edge could answer most requests and the origin load would collapse.
It also risks a serious boundary error. The page may vary by session, locale, experiment, account state, or authorization. If the edge key does not distinguish those meanings, a copy created for one request can be served to the wrong audience. Even when no private field leaks, an aggressively shared page can make a learner see a stale enrollment state or a price that should have been checked elsewhere.
The opposite naive model is “only Redis is safe.” That wastes the delivery path. A browser that already has app.8b9f.js should not open a network connection so the API can retrieve a copy of that bundle from Redis. A public image served from a nearby edge avoids distance, bandwidth, connection work, and origin concurrency all at once.
The better question is deliberately narrower:
Can this response be shared at this layer without violating its audience or freshness promise?
A Layered Cache Boundary
Use the landing page components as a design map.
| Representation | Audience and change pattern | Reuse boundary | Why | Do not assume |
|---|---|---|---|---|
app.8b9f.js |
Public; filename changes when content changes | Browser and CDN edge, long-lived | The versioned name points to one immutable edition | A changing file at a stable URL has the same safety |
| Course thumbnail | Public; edits are infrequent | CDN edge and browser, policy-limited | Many visitors need identical bytes | An image change instantly reaches every existing copy |
| Public course catalogue | Public; edits occur during the day | Edge for a short trust window or validation, then origin/Redis | Repeated public reads can avoid much origin work | A hit proves the catalogue is current forever |
| “Your enrolled courses” | Personal; varies by identity | Private browser policy or origin, depending on the product contract | Its audience is one learner | A response is safe to share merely because the route is a GET |
| Seat availability / checkout price | Correctness-critical decision | Authoritative service at decision time | The action needs current controlled state | A display cache is enough evidence to accept the action |
The table does not prescribe a vendor configuration. It names the ownership boundary. CDN configuration, route rules, and exact HTTP controls should implement this classification rather than invent it after the fact.
A Worked Request Trace
Assume a learner in Madrid opens the public course page. The page refers to app.8b9f.js, /images/course-204.webp, and GET /api/public/courses/204. The learner is not yet signed in.
| Step | Request or state | Layer that decides | Result |
|---|---|---|---|
| 1 | Browser requests app.8b9f.js again |
Browser cache | Its valid versioned copy is used. No network request leaves the device. |
| 2 | Browser needs the course image | CDN edge | The Madrid edge has an acceptable public copy and returns it. The origin sees nothing. |
| 3 | Browser requests public course details | CDN edge | The entry is absent or no longer trusted, so the edge forwards toward the origin. |
| 4 | Origin receives the public API request | API and shared Redis | Redis has a policy-acceptable course-details value, so the API avoids a database read. |
| 5 | Origin responds with its reuse policy | Browser and edge | They may store or later validate the public representation according to that policy. |
| 6 | Learner signs in and asks for enrollment state | Origin/application | The request follows its private, identity-aware path; it is not satisfied from the public course response. |
This trace contains two different savings. The asset and image hits remove origin work entirely. The public API request reaches the origin but may still avoid database work through Redis. These are complementary layers, not competing products.
Now imagine the course editor changes the public description. A browser or edge may still have an older allowed copy. Whether that is acceptable is not an accident of cache placement; it is a product choice recorded in the freshness policy. The next lesson studies how the system moves readers from that old copy to a newer one and how it avoids a refill burst when copies expire.
From Plain Policy to HTTP Signals
The origin needs to communicate the policy to clients and intermediaries. A simplified public catalogue response might carry signals like these:
Cache-Control: public, max-age=60
ETag: "course-204-public-v42"
Read the example as a contract, not as magic syntax:
publicsays that a shared intermediary may reuse this representation if the rest of the policy permits it.max-age=60gives a bounded period in which it may be reused without asking the origin again.- the
ETagnames the current representation so a cache can later ask whether its copy is still the same instead of always transferring the full response.
For a versioned bundle, the safe policy can often be much longer because a new deploy creates a different URL. For a personal response, shared reuse should not be inferred from the convenience of adding a header. The origin must first know the audience, variation inputs, and privacy consequences.
A useful discipline is to write the policy before the header:
Public catalogue: any anonymous visitor may reuse the same representation
for up to 60 seconds; after that, confirm whether it changed.
Only then translate it into HTTP behavior and an edge rule. If the team cannot write that sentence clearly, it is not ready to cache the route broadly.
Trade-offs and Failure Boundaries
The central trade-off is lower latency and lower origin work versus less immediate control over copies that now exist outside the application. A browser or edge hit can be extraordinarily cheap, but it also means the origin does not observe that request and cannot silently correct the response on every view.
An edge hit is not automatically a good hit
A high edge hit rate can hide a poor policy. If it comes from caching a personalized response under a broad key, the “performance gain” is a privacy incident. If it comes from serving a catalogue beyond its agreed freshness budget, it is a product-correctness regression. Measure hit rate beside response class, origin load, stale-content reports, and the user promise.
The cache key must reflect the representation
The key is not merely the URL string. If language, device format, authentication state, or a selected experiment changes the meaning of the response, the cache policy must account for that variation or avoid shared caching. Otherwise two requests that look alike to the cache may not be equivalent to users.
Origin fallback must have capacity
An empty edge, an expired browser entry, or an edge incident can send traffic back to the origin together. Redis may reduce the database part of that load, but it does not erase API concurrency, serialization, authentication, or outbound calls. The origin needs a failure budget for the “all paths fall through” case.
Do not hide a decision behind a display cache
Showing “3 seats left” from a briefly cached public response can be fine. Accepting the fourth enrollment based only on that response is not. The action must recheck the state at its authoritative boundary. Caching can improve the read path without becoming evidence for a critical write.
This layer is useful for public, repeatable representations and versioned assets. It is not a substitute for identity-aware authorization, transactional decisions, or a complete invalidation strategy.
Common Confusions
Confusion: A CDN is just Redis located farther away
Why it is tempting:
Both can return a stored value and lower load on a database or service.
Better model:
Redis is an application-managed shared layer behind the origin. Browser and CDN caches participate in the delivery path and follow HTTP visibility, freshness, and validation policy. A request can hit Redis only after it reaches the application; a valid edge hit prevents that request altogether.
Confusion: public means that the route contains no secret today
Why it is tempting:
The response currently looks harmless in a manual test.
Better model:
Public reuse is a durable audience claim. Review every input that can vary the representation: identity, cookies, locale, experiment, tenant, and authorization. A later product change can turn a once-safe shared rule into a leak.
Confusion: Caching a response decides whether the corresponding action is safe
Why it is tempting:
The displayed value and the action refer to the same course or inventory record.
Better model:
A read cache can make a display fast. The write path must still use the authority and concurrency control required by the action. Caching is a reuse policy, not an authorization or transaction policy.
Check Your Understanding
Check: A learner loads a versioned bundle and the browser serves it from local cache. Which components did the request avoid, and why is that different from a Redis hit?
Think first, then reveal.
Answer: It avoided the network, CDN, origin, API, Redis, and database for that request because the browser already held the exact version named by the URL. A Redis hit still requires the request to reach the origin application before it can reuse the shared value.
Check: The public catalogue and the signed-in enrollment panel are assembled on the same HTML page. May the CDN cache the complete rendered page as one public object?
Think first, then reveal.
Answer: Not without proving that the complete representation has one public audience and one compatible variation policy. The enrollment panel makes the page identity-dependent. Split the public and personal boundaries, or use a private/origin path for the combined response.
Check: An edge cache serves a course description that is 45 seconds old, while the source changed 20 seconds ago. Is that automatically a bug?
Think first, then reveal.
Answer: No. It is acceptable only if the response's stated freshness budget permits it. The mistake is not “old data exists”; the mistake is failing to define whether that age is acceptable and how readers move to the new version afterward.
Practice
For each item below, write one sentence with (1) the audience, (2) the first reuse layer you would allow, and (3) the consequence if it is stale or shared incorrectly.
- A font file whose URL contains a content hash.
- A public list of upcoming courses edited several times per day.
GET /me/payment-methodsfor a signed-in learner.- A banner showing “registration closes tonight.”
Then draw the request path for item 2 and mark where an edge miss can still become a Redis hit at the origin. Do not choose a TTL first; write the freshness promise first. Compare your choices with the classification table above, and explain one item that must remain authoritative at action time even if its display is cacheable.
Resources
- [DOC] MDN: HTTP caching — Focus: connect freshness, validation, and response visibility to the policy written in this lesson.
- [SPEC] RFC 9111: HTTP Caching — Focus: consult the authoritative semantics after you can state the audience and freshness contract in plain language.
- [DOC] Cloudflare Cache documentation — Focus: see how an edge platform exposes cache controls without confusing product policy with vendor configuration.
Key Takeaways
- Cache location changes the saved work. A browser or edge hit avoids origin work entirely; a shared Redis hit only avoids work behind an origin request.
- Classify before configuring. Audience, change pattern, and freshness budget determine whether and where a representation may be reused.
- A cache policy is a product promise. High hit rate is valuable only when privacy, correctness, and origin-fallback behavior remain inside that promise.
← Back to Caching, Workers, and Performance