Dynamic Content Caching: When and How to Cache the Uncacheable

· Alex Petrov · 9 min read

Dynamic content has traditionally been considered uncacheable. Pages that change based on the user, the time of day, inventory levels, or real-time data appear to require a fresh origin response for every request. This assumption leaves enormous performance gains on the table. In reality, most dynamic content changes far less frequently than the request rate demands, and a range of techniques exist to cache it at the CDN edge without serving stale or incorrect data. From micro-caching to Edge Side Includes, these approaches transform high-cost origin renders into low-latency edge responses.

What Counts as Dynamic Content?

Dynamic content is any response generated at request time by application logic rather than served from a static file. The spectrum ranges from slightly dynamic to fully personalized: For foundational context, read CDN Caching Strategies: Pull, Push, and Hybrid — FlyFish NWA.

Content typeChange frequencyPersonalizedCacheability
Blog homepage with latest postsEvery few minutesNoHigh with short TTL
Product listing pageMinutes to hoursNoHigh with short TTL
Search resultsReal-timeBy queryMedium, key by query
Shopping cartPer interactionPer userLow, bypass or fragment
Dashboard with live metricsSecondsPer userLow, micro-cache only
Checkout and paymentPer interactionPer sessionNone, always bypass

The key insight is that most dynamic content is not personalized. A product listing page showing the same items to every visitor is technically dynamic because the server renders it from a database query, but the output is identical for all users. This content is an immediate candidate for edge caching with an appropriate TTL strategy.

CDN Cache Hierarchy — Multi-tier caching architecture from edge to originCDN Cache Hierarchy — Multi-tier caching architecture from edge to origin CDN Cache Hierarchy — Multi-Tier Architecture L1 Edge Cache Hit Rate: 95% Latency: < 5ms miss L2 Regional Cache Hit Rate: 85% Latency: 10–30ms miss Origin Shield Hit Rate: 70% Latency: 50–80ms miss Origin Server Hit Rate: — Latency: 100–300ms
Figure 1: CDN Cache Hierarchy — Multi-tier caching architecture from edge to origin

What Is Edge Side Includes and How Does It Enable Fragment Caching?

Edge Side Includes is a markup language that allows CDN edge servers to assemble pages from independently cacheable fragments. Instead of caching an entire page as one unit, ESI breaks it into components, each with its own TTL and cache key.

Performance Comparison: Edge vs Origin Processing
Metric Edge Processing Origin Processing Improvement
Latency (p50)8–15 ms120–300 ms15–20x faster
Cache Hit Ratio85–95%N/AReduces origin load
TLS Handshake1–5 ms (nearby PoP)50–150 ms10–30x faster
Bandwidth Cost$0.01–0.04/GB$0.05–0.12/GB3–5x cheaper
Availability99.99% (multi-PoP)99.9% (single DC)10x fewer outages

The origin sends a response containing ESI include directives:

<!-- Page shell cached for 1 hour -->
<header>
  <esi:include src="/fragments/nav" />
</header>
<main>
  <h1>Product Details</h1>
  <div class="product-info">...static content...</div>
  <div class="pricing">
    <esi:include src="/fragments/price?sku=ABC123" />
  </div>
  <div class="reviews">
    <esi:include src="/fragments/reviews?sku=ABC123" />
  </div>
</main>

Each fragment can have independent cache settings:

The CDN fetches each fragment independently, assembles the complete page, and serves it to the user. If the navigation is cached but the price fragment has expired, only the price fragment triggers an origin fetch. This granularity maximizes cache efficiency while maintaining freshness where it matters.

ESI is supported by Varnish, Akamai, Fastly, and several other CDN providers. For a deeper understanding of ESI implementation patterns, see the Edge Side Includes guide.

How Does Micro-Caching Work for High-Traffic Dynamic Pages?

Micro-caching stores responses for very short durations, typically one to five seconds. The technique is deceptively powerful. For a page receiving 1,000 requests per second, a one-second micro-cache means 999 of those requests are served from cache and only one reaches the origin.

Configure micro-caching in Nginx:

proxy_cache_path /var/cache/nginx/micro levels=1:2
    keys_zone=micro:10m max_size=1g inactive=1m;

location /api/feed {
    proxy_cache micro;
    proxy_cache_valid 200 1s;
    proxy_cache_use_stale updating;
    proxy_cache_lock on;
    proxy_pass http://app_server;
}

The combination of a one-second cache, proxy_cache_use_stale updating, and proxy_cache_lock on creates a powerful pattern. The lock ensures only one request per second reaches the origin. The updating stale directive serves the previous response while the new one is being fetched, eliminating any latency spike at the cache boundary. This is essentially stale-while-revalidate at the proxy level.

Micro-caching works best for pages where one-second staleness is acceptable:

How Can You Cache Personalized Content at the Edge?

Personalization is the hardest dynamic content to cache because the response varies per user. Several strategies address this challenge, each with different tradeoffs:

Cache Decision Flow — How the CDN determines cache hit vs missCache Decision Flow — How the CDN determines cache hit vs miss CDN Request Flow — From Browser to Edge CDN Request Lifecycle Step 1 DNS Lookup Step 2 TCP Connect Step 3 TLS Handshake Step 4 Edge Server Step 5 Cache Check Step 6 Response Cache HIT → 5ms response Cache MISS → Fetch origin 0ms ~50ms (cache hit) ~200ms (cache miss)
Figure 2: Cache Decision Flow — How the CDN determines cache hit vs miss

Edge-Side Assembly

Separate the shared page shell from personalized elements using ESI. Cache the shell for hours and fetch personalized fragments per request. The shell, which includes layout, navigation, product details, and images, represents 80-90% of the page payload. Only the personalized fragments such as user name, cart count, and recommendations need per-request fetching.

Client-Side Personalization

Cache the complete generic page at the CDN and load personalized elements via browser-side API calls after the page renders. This approach is increasingly common in modern single-page applications:

  1. CDN serves a cached, generic product page instantly.
  2. After page load, the browser fetches /api/user/recommendations and /api/user/cart-count.
  3. These API calls either bypass CDN cache or use short TTLs.
  4. The browser injects personalized content into the already-rendered page.

The user perceives a fast page load because the bulk of the content arrives from the edge cache. Personalized elements appear moments later, often before the user even notices the delay.

Cookie-Based Cache Bypass

The simplest personalization strategy bypasses the CDN cache entirely for logged-in users while serving cached content to anonymous visitors. Since anonymous traffic typically represents 70-90% of total traffic on most sites, this approach still provides substantial origin protection.

# Varnish VCL: bypass cache for logged-in users
sub vcl_recv {
    if (req.http.Cookie ~ "session_id") {
        return (pass);
    }
}

This is effective but leaves significant optimization potential untapped. Logged-in users still benefit from edge proximity for TLS termination, connection pooling, and content routing, but their HTML responses always come from the origin.

What Is the Short TTL Plus SWR Pattern?

Combining short TTLs with stale-while-revalidate is the most versatile pattern for dynamic content caching. The short TTL ensures content stays reasonably fresh, while SWR eliminates the latency penalty of cache misses:

Cache-Control: public, max-age=10, stale-while-revalidate=50

This header tells the CDN to serve content from cache for 10 seconds. Between 10 and 60 seconds, serve the stale version instantly while fetching a fresh copy in the background. The user never waits for an origin response, and the content is never more than 60 seconds old.

For a page with 500 requests per second, this pattern reduces origin load from 500 to approximately one request every 10 seconds while keeping content no more than a minute stale. Configure appropriate Cache-Control headers to implement this at scale.

The short TTL + SWR pattern also naturally prevents cache stampedes. Because SWR triggers a single background revalidation rather than allowing all requests to hit the origin when the TTL expires, the origin never sees a traffic spike at the cache boundary.

How Do You Implement A/B Testing with Edge Caching?

A/B testing introduces a variant dimension to caching. Each user should consistently see the same variant, but the CDN should cache each variant separately rather than sending every request to the origin.

The recommended approach uses CDN edge logic to assign and persist variants:

  1. The edge checks for an existing variant cookie on the request.
  2. If no cookie exists, the edge assigns a variant based on a hash of the user identifier or a random selection.
  3. The edge sets the variant as part of the cache key, creating separate cached versions for variant A and variant B.
  4. The response includes a Set-Cookie header to persist the variant assignment.

This approach ensures that the CDN caches two versions of each page, one per variant, rather than bypassing cache entirely for A/B testing. The origin only needs to generate each variant once per TTL per edge PoP.

How Do API Responses Benefit from Edge Caching?

API responses are often treated as entirely uncacheable, but most API traffic falls into patterns that benefit from caching:

API patternCaching approachRecommended TTL
Public catalog or listingStandard cache with SWR30 seconds to 5 minutes
Search with query parametersCache keyed by query string60 seconds to 5 minutes
User profile or preferencesCache per user token5 to 60 seconds
Real-time pricing or inventoryMicro-cache1 to 5 seconds
Write operations (POST, PUT, DELETE)Never cacheNot applicable

For authenticated API responses, include the authorization token or user identifier in the cache key. This creates per-user cache entries that can still serve repeated requests from the same user without hitting the origin. Be mindful of cache key fragmentation, though. If every user has a unique cache entry, the effective hit ratio may be too low to justify the storage overhead.

What Are the Risks of Caching Dynamic Content?

Caching dynamic content carries risks that do not exist with static assets:

Despite these risks, the performance benefits of caching dynamic content are substantial. A well-configured dynamic caching strategy typically improves your cache hit ratio by 20-40 percentage points while maintaining acceptable content freshness. The key is understanding which content can tolerate staleness, decomposing pages into cacheable fragments, and using short TTLs with SWR to minimize the freshness gap. Combined with proper cache hierarchy design, dynamic content caching transforms your CDN from a static asset server into a full-stack performance layer.

External References

References & Standards: OWASP CDN Security · W3C Web Performance