A browser cache belongs to one user agent; a shared edge cache can serve many viewers. That audience difference is the first cache policy decision. Public immutable assets may be reused broadly, while account-specific case HTML must never enter a shared cache under a key that another viewer can hit. The URL alone is not always a complete representation key: language and content encoding may vary by request header. The Vary response field tells a cache which request headers changed the representation, but it is not a substitute for private-cache policy when the response depends on a login cookie. Make response ownership explicit before tuning time-to-live or purge rules.
Shared Cache Keys and Private Response Boundaries
Working case
A review dashboard at the same URL renders case counts for reviewer 29 and reviewer 62. A shared edge rule caches the first HTML response by URL and serves its counts to the second reviewer. Adding Vary: Cookie seems tempting, but it creates many variants and still treats private HTML as shared material. Mark the response private or prevent storage according to the sensitivity and session design. Keep the public application shell and versioned static files separately cacheable. For the public help page, a language variant may need a URL or an appropriate Vary key.
Implementation boundary
function cacheAudience(responseKind) {
if (responseKind === "private-case-html") return "private, no-store";
if (responseKind === "versioned-asset") return "public, max-age=31536000, immutable";
return "public, max-age=120";
}
console.log(cacheAudience("private-case-html"));
// Output: private, no-storeThe simple policy table is a starting contract, not a complete header parser. A production response may also use an ETag and validation policy, but first isolate private data from shared storage. Check every layer: origin, reverse proxy, edge, service worker, and browser. A public response selected by Accept-Language or Accept-Encoding needs consistent variant handling, including validation responses. Prefer language-specific paths when they are part of product navigation, and avoid unbounded Vary dimensions such as full user-agent strings. Test with two accounts and cold plus warm caches, inspecting actual response bodies and cache-status headers.
Cost and boundaries
A public asset cache can cut repeat transfer and origin work; a private no-store response does not receive that reuse. If a cache has v independent header variants, storage and miss rate can grow with v, and multiplying several dimensions can grow quickly. One long immutable asset lifetime is safe only when a content change produces a new URL. Preventing private leakage takes precedence over a higher hit rate. Measure correct representation delivery, origin load, and cache hit rate together; a hit that returns the wrong viewer's data is a severe defect, not a performance success.
Failure trace
A staging test uses only one account, so the dashboard's shared cache appears fast and correct. In production a second account sees the first account's case count. Purging the cache repairs the current object but leaves the policy bug; the next response can leak again. Partition public and private routes, set ownership headers, and add a two-account edge test. A separate language defect occurs when one public URL returns multiple languages without a variant key: a warm cache serves the wrong language until expiry. Include the request dimension or use distinct locale URLs.
Verification
- Two accounts never receive each other's private HTML from a warm edge.
- Public language variants remain correct after warm-cache requests.
- A changed immutable asset receives a new URL.
Practice drill
Request the dashboard as account 29, then as account 62, with the edge cache enabled. Compare HTML bodies, response headers, and cache-status metadata. Try a public localized guide twice with different language preferences, then verify that its representation key is correct. Change a versioned JavaScript asset without changing its filename in a controlled branch and observe why a long immutable lifetime keeps old bytes. Restore content-hashed filenames, then repeat after sign-out and service-worker interception.
Decision note
Assign a response to its intended audience first, then define the complete public variant key and lifetime.
Common Mistakes
- Using Vary: Cookie as the only private-data barrier.
- Caching authenticated HTML in a shared URL bucket.
- Giving unversioned files a year-long immutable lifetime.
Connected lessons
HTTP Delivery and Cache Ownership; Stale Revalidation and Versioned Purges; Content Negotiation and Compression Contracts; Critical Resource Discovery and Priority; HTTP caching: validate a changed representation with an ETag; Authorization: check permission for this record on every request; Localized Routes and Translation Release.
Apply and check
Build Project: edge cache and critical resource release and review Web Development: navigation and delivery decisions quiz.
Further connections
Tenant Scope in Cache and Background Work.
