Networking, caching & HTTP for UIs
Frontend networking is product behavior. The same cache header that makes a page fast can leak stale personalization, hide failed mutations, or make an incident hard to roll back. Senior frontend engineers can explain both browser mechanics and ownership rules.
Core details
| Concern | Key ideas |
|---|---|
| Critical path | DNS/TCP/TLS, redirects, HTML, render-blocking CSS, module graph, fonts, LCP media |
| Versioning | content-hashed assets can use long immutable caching safely |
| HTML policy | personalized HTML should be short-lived, private, or keyed carefully |
Cache-Control | max-age, s-maxage, stale-while-revalidate, no-store, private, public |
| Validators | ETag / Last-Modified allow 304 revalidation when object identity is stable |
| Speculation | prefetch/prerender only when intent and freshness rules justify the cost |
| Mutation path | retries, idempotency, cancellation, duplicate-submit protection |
Cache policy examples:
Cache-Control: public, max-age=31536000, immutableUse for content-hashed JS, CSS, and image assets. Never reuse the same URL for different bytes.
Cache-Control: private, no-storeUse for sensitive personalized responses where browser or proxy storage would be unsafe.
Cache-Control: s-maxage=60, stale-while-revalidate=300Use carefully at a CDN for shared, non-sensitive data where brief staleness is acceptable and purge/revalidation ownership is clear.
CDN ownership: dynamic edge caching needs a purge story: surrogate keys, path bans, tag invalidation, deploy ordering, and an incident command to bypass cache quickly.
Understanding
Most win comes from changing what ships and in what order, not from squeezing bits. Hash-versioned static assets can safely live at long TTLs; HTML and personalized responses almost never should without strict keying and purge discipline. GET APIs cached for “speed” can lie to the UI about business truth—pair caches with explicit freshness contracts and user-visible cues when data may be stale.
HTTP caching has three separate audiences:
- Browser cache: helps one user avoid repeat downloads.
- CDN/shared cache: reduces origin load and global latency but must not mix users or tenants.
- Application/data cache: controls business freshness and often needs explicit invalidation after mutations.
Do not collapse these into one “cache is fast” bucket. A product page image, a logged-in account page, and a cart count have different correctness contracts.
The visual model below separates those contracts: immutable hashed assets can live long, personalized HTML needs private or keyed handling, and API mutations must invalidate the UI state they make stale.

Practical examples
| Situation | Recommended stance | Why |
|---|---|---|
Hashed app.abcd123.js | Long public, immutable | URL changes when bytes change |
| Logged-in dashboard HTML | private or no-store, or framework dynamic render | Avoid cross-user and stale auth bugs |
| Search suggestions | Short shared cache if query/key is anonymous | Staleness is usually acceptable |
| Cart mutation | POST with idempotency key; invalidate cart query | Prevent duplicate purchases and stale badge |
| Retry after network error | Retry safe/idempotent operations; ask on ambiguous writes | Avoid accidental duplicate side effects |
Request cancellation: use AbortController when a newer request supersedes an older one. Otherwise slow responses can overwrite newer UI state.
const controller = new AbortController();
fetch(`/api/search?q=${encodeURIComponent(query)}`, {
signal: controller.signal,
});
return () => controller.abort();Senior understanding
| Probe angle | Credibility artifact |
|---|---|
| “Prove regression” | Network waterfall screenshot before/after with identical throttle profile |
| “Who owns keys?” | cross-team SLA on purge events / surrogate invalidation choreography |
| “Security posture” | zero mixed-content; strict transport headers alignment awareness |
| “Freshness vs speed?” | product-specific stale UI budget and explicit revalidation event |
Third-party weight: escalate marketing injectables through risk review—SLO-aware loading, deferred consent-aware activation, kill switches—not “marketing exception” culture.
Failure modes
- Caching personalized HTML as
publicwithoutVary, user/tenant keying, or purge discipline. - Using
stale-while-revalidatefor data where stale values cause user harm. - Preloading many assets and delaying the actual LCP resource.
- Retrying non-idempotent POST requests after a timeout without an idempotency key.
- Letting old async responses win races against newer user input.
Interview drill
Question: "After deploy, logged-in users sometimes see stale account data. How do you debug the cache stack?"
Model answer structure:
- Identify the stale surface: HTML, RSC/server payload, API response, client query cache, CDN, or browser cache.
- Inspect response headers, cache keys,
Vary, authentication signals, and whether the route is static or dynamic. - Check mutation flow: what cache boundary is invalidated, by whom, and whether old responses can race newer state.
- Apply a correctness-first fix: private/no-store for sensitive HTML, safe keying, tag/path invalidation, or shorter stale budget.
- Add regression guardrails: release-tagged logs, cache header tests, and an incident bypass/purge command.
Follow-ups to expect:
- "Why is CORS not the same as authorization?"
- "When is
stale-while-revalidateunsafe?" - "How would you cache a public product page differently from a dashboard?"
Diagram
See also
Mark this page when you finish learning it.
Spotted something unclear or wrong on this page?