CDN Edge Caching
debt(d7/e3/b5/t7)
Closest to 'only careful code review or runtime testing' (d7). Tools listed (Lighthouse, Cloudflare, Fastly, Varnish) can surface missing Cache-Control headers or caching anomalies, but misconfigured caching — especially authenticated responses being cached or Vary headers being wrong — typically only manifests in production under real traffic conditions. Lighthouse can flag missing cache headers on static assets, but the more dangerous mistakes (caching user-specific responses) are silent until a user reports seeing another user's data.
Closest to 'simple parameterised fix' (e3). The quick_fix indicates setting Surrogate-Control or Cache-Control headers on PHP responses, which is a targeted header addition. However, fixing the full set of common_mistakes (content-hashed filenames, Vary headers, separating authenticated from public responses) touches multiple response paths and may require reviewing several controllers or middleware, making it slightly more than a one-liner but still within a single component scope.
Closest to 'persistent productivity tax' (b5). CDN caching configuration applies to all public-facing web responses in the PHP application. Every new endpoint or page added must consider whether it is cacheable, what Cache-Control values to set, and how to handle cache invalidation. This is an ongoing productivity tax across many work streams (new features, API endpoints, asset pipelines) without reshaping the entire architecture.
Closest to 'serious trap' (t7). The misconception field states explicitly: developers assume CDN caching is automatic, leading to two opposite failure modes — either nothing is cached (wasted infrastructure) or everything is cached including authenticated responses (security/correctness violation). This directly contradicts reasonable developer intuition about how CDNs behave by default, and the 'cache everything' failure mode has security implications beyond just performance. This is a well-documented gotcha that contradicts how server-side caching (e.g., opcode caches, database caches) works elsewhere.
Also Known As
TL;DR
Explanation
A CDN sits between users and your origin server. Edge nodes cache responses based on Cache-Control directives: max-age (how long to cache), s-maxage (CDN-specific, overrides max-age), stale-while-revalidate (serve stale while fetching fresh), stale-if-error (serve stale on origin error). Vary header tells the CDN which request headers produce different responses. Cache purging invalidates content before expiry. For PHP: static assets get long max-age with content-hashed filenames; API responses need short max-age or no-store for authenticated content.
Diagram
flowchart TD
REQ[User Request] --> EDGE{CDN Edge<br/>has cached response?}
EDGE -->|HIT - serve from edge| FAST[Response in ms<br/>origin not contacted]
EDGE -->|MISS| ORIGIN[Origin Server]
ORIGIN -->|response + Cache-Control| EDGE
EDGE -->|cache and serve| USER[User]
subgraph Cache-Control Headers
PUB[public s-maxage=60<br/>CDN caches 60s]
PRIV[private no-store<br/>CDN never caches]
IMM[max-age=31536000 immutable<br/>hashed assets - 1 year]
end
style FAST fill:#238636,color:#fff
style PUB fill:#238636,color:#fff
style PRIV fill:#d29922,color:#fff
style IMM fill:#238636,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- No Cache-Control header — CDN may cache nothing or cache everything including user-specific responses.
- Caching authenticated API responses — user A's data served to user B when auth headers vary.
- Not using content-hashed filenames for assets — short max-age on static assets kills CDN hit rate.
- Forgetting Vary: Accept-Encoding — CDN serves gzip response to client that cannot decompress it.
Code Examples
// No cache headers — CDN caches nothing or caches incorrectly:
function sendResponse(array $data): void {
header('Content-Type: application/json');
// No Cache-Control — CDN guesses or caches authenticated responses!
echo json_encode($data);
}
// Explicit cache control per content type:
// Public API data — CDN caches for 60s:
header('Cache-Control: public, s-maxage=60, stale-while-revalidate=300');
// Authenticated data — never cache at CDN:
header('Cache-Control: private, no-store');
// Static assets with content hash in filename:
// app.a3f2c1.js — safe to cache for 1 year:
header('Cache-Control: public, max-age=31536000, immutable');