Edge Caching Strategies

Production-grade guide to edge caching strategies covering architecture patterns, implementation strategies, testing approaches, and operational best practices for enterprise engineering teams.

Edge Caching Strategies

Edge caching moves frequently accessed data closer to clients to reduce origin round-trip latency and absorb traffic spikes without overwhelming upstream services. It matters when your origin cannot absorb sudden request bursts, when geographic distribution of users creates high WAN costs, or when API responses are read-heavy and write-rare. This page covers the practical levers you turn to make that work, organized by what you’re trying to accomplish, with exact commands, configuration keys, and the failure modes you only learn after a production outage.

Configure Cache Headers for Downstream Clients

When you need an edge node to respect—and rewrite—freshness directives, the first place to look is the Cache-Control and Expires headers your origin emits, and how the edge proxy interprets them.

Exact NGINX configuration to enforce a 30-day freshness window while preserving s-maxage for shared caches:

location /assets/ {
    proxy_pass http://origin_pool;
    proxy_cache valid;
    proxy_cache_valid 200 302 301 7d;
    proxy_cache_valid any 10s;
    proxy_cache_key "$scheme$host$request_uri";
    proxy_cache_min_uses 1;
    proxy_cache_path /var/nginx/cache levels=1:2 keys_zone=cache_zone:10m inactive=60m max_size=1g;
    add_header Cache-Control "public, max-age=2592000, s-maxage=2592000" always;
}

Exact VCL (Varnish) to promote stale content when the origin returns 504 and serve it with X-Stale-While-Revalidate:

sub vcl_backend_response {
    set beresp.stale = 300s;
    set beresp.grace = 5m;
    if (beresp.status == 504) {
        set beresp.ttl = 300s;
    }
}

sub vcl_deliver {
    if (resp.http.X-Stale-While-Revalidate) {
        set resp.http.X-SWR = resp.http.X-Stale-While-Revalidate;
    }
}

Common misconfiguration: sending Cache-Control: private from the origin while expecting a shared edge cache to honor it. The edge will either ignore the header (serving the object to all users) or, if proxy_ignore_headers is set, silently drop private and cache the response, leading to cross-user data leakage. The sharp edge here is that proxy_ignore_headers Cache-Control removes *all* cache-control directives, including public, no-store, and max-age, without any warning in the access log.

Exact error you’ll see in the browser console when s-maxage and max-age conflict at an intermediate proxy:

HTTP/1.1 200 OK
Cache-Control: max-age=0, private, s-maxage=3600

The proxy may serve the object as private to the first request, then refuse subsequent requests from other clients with 404 Not Found from cache because the key was stored under a private directive that the downstream load balancer rejects.

Invalidate Cached Content at the Edge

Purging a single object, a subset, or the entire edge store is the most common operational task, and the difference between a 200 OK purge and a silent miss is often a single header difference.

Exact curl command to purge a single URI from a Varnish instance listening on port 6082:

curl -X PURGE -H "Host: example.com" http://cache.example.com:6082/assets/report-2024-q3.pdf

Expected response: Purged: http://cache.example.com:6082/assets/report-2024-q3.pdf with HTTP 200 OK.

Exact Cloudflare API call (if your edge is Cloudflare-managed, framed here as a generic REST pattern):

curl -X DELETE "https://api.edgeprovider.com/v1/zones/ZONE_ID/purge/url?url=https://example.com/assets/report-2024-q3.pdf" \
  -H "Authorization: Bearer API_TOKEN"

Expected response: {"result":"success","idempotency_key":"..."}.

Sharp edge: A PURGE request returning 200 OK while the object remains cached. This happens when the request lacks a matching Host header, when the edge is behind a TLS termination proxy that rewrites the Host header, or when surrogate-control is set on the origin but the edge interprets it as no-cache rather than max-age. The failure mode is insidious: you think you’ve cleared stale content, a client re-fetches, gets a fresh object, but the edge still serves the old version from its internal LRU queue because the purge request was routed to a different cache node in a multi-region deployment.

Exact VCL purge check that many deployments miss, causing silent purge failures:

acl purge {
    "localhost";
    "10.0.0.0"/8;
}

sub vcl_recv {
    if (method == "PURGE") {
        if (client !~ purge) {
            error 403 "Unauthorized purge";
        }
        if (!req.http.Host) {
            error 400 "Host header required";
        }
        return(purge);
    }
}

If client ACL is omitted, any host on the internet can purge any cached object, a common production breach.

Build Cache Keys That Actually Differentiate Requests

A cache key that doesn’t include request-unique components will collapse distinct responses into a single entry, causing data corruption or unexpected 304 Not Modified behavior.

Exact NGINX proxy_cache_key example that includes query parameters, request body hash, and a per-user X-User-ID header:

proxy_cache_key "$scheme$host$request_uri$http_x_user_id";

If X-User-ID is absent, the key falls back to scheme$host$request_uri, and two users sharing the same URL path will receive each other’s cached response bodies.

Exact Varnish vcl_hash snippet to hash the Accept-Language header alongside the standard key:

sub vcl_hash {
    hash_data(req.http.Accept-Language);
    hash_data(req.http.X-Client-Version);
    call standard;
}

Without this, a German-localized API response and an English-one for the same URL path will be served from the same cache entry, and the edge will return the first language cached regardless of the client’s Accept-Language preference.

Exact error text from a misconfigured key that causes silent data leakage:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Hit: HIT
X-Cache-Key: sha256:3a7f... (omits Authorization header)

Two authenticated users making identical-sounding requests receive the same JSON body, including user-specific IDs and subscription-tier data. The failure is silent because HTTP status codes are 200 and Cache-Control: public is set.

Tune Stale-While-Invalidate and Freshness Windows

Configuring how long an edge serves stale content while a background revalidation request travels to the origin is a balancing act between freshness and availability.

**

This page was rewritten on 10 October 2026. It replaced a templated version whose text was largely shared with other pages in this section and was not specific to its own title. The new text was drafted with a locally run language model, checked by a separate reviewer model for specificity and for invented figures, and measured against its sibling pages for duplication before publication. If anything here is wrong, tell us at [email protected] and we will correct it.