Why Cache Testing Matters
Caching dramatically improves web performance by storing copies of resources so they do not need to be fetched from the server every time. However, incorrect caching leads to users seeing outdated content, receiving stale API responses, or experiencing broken pages after deployments.
The famous quote “There are only two hard things in computer science: cache invalidation and naming things” exists because caching bugs are notoriously difficult to reproduce and debug.
Cache Layers
Each layer can independently cache and serve stale content.
Browser Cache
Stores resources locally on the user’s device. Controlled by Cache-Control and ETag response headers.
CDN Cache
Stores copies at edge locations worldwide. Reduces latency by serving content from the nearest server.
Server-Side Cache
Application-level caching (Redis, Memcached) that stores computed results, database queries, or API responses.
Key Cache Headers
| Header | Purpose | Example |
|---|---|---|
Cache-Control | Primary caching directive | max-age=3600, public |
ETag | Content fingerprint for validation | "abc123def456" |
Last-Modified | When content was last changed | Tue, 19 Mar 2026 10:00:00 GMT |
Expires | Absolute expiration date (legacy) | Tue, 19 Mar 2026 11:00:00 GMT |
Vary | Cache varies by request header | Vary: Accept-Encoding, Accept-Language |
Cache-Control Directives
| Directive | Meaning |
|---|---|
public | Can be cached by any cache (browser, CDN, proxy) |
private | Can only be cached by the user’s browser |
no-cache | Must revalidate with server before using cached copy |
no-store | Must not be cached at all |
max-age=N | Cache is valid for N seconds |
s-maxage=N | CDN/proxy cache duration (overrides max-age for shared caches) |
immutable | Content will never change — browser can skip revalidation |
What to Test
Correct Caching Behavior
| Resource Type | Expected Caching | Why |
|---|---|---|
| Static assets (JS, CSS, images) | Long cache (1 year) with hash in filename | Content-addressable, cache busting handles updates |
| HTML pages | Short cache or no-cache | Content changes frequently |
| API responses (public data) | Short cache (minutes) | Balance freshness and performance |
| API responses (user-specific) | private, no-cache or no-store | Prevent data leakage between users |
| Authentication endpoints | no-store | Sensitive data must never be cached |
Cache Invalidation After Deployment
- Deploy a change to CSS/JS
- Verify that users get the new version (check file hash in URL changed)
- Verify old cached version does not break the new HTML
- Test with the browser cache populated from before the deployment
Stale Content Scenarios
- Update a product price — does the old price persist in any cache?
- Change a user’s role — do cached permission checks still show old role?
- Delete content — does the cached version still serve the deleted page?
- Update a profile image — does the old image persist?
Cache and Authentication
- User A’s data must never be served from cache to User B
- Logging out must invalidate cached user-specific content
Vary: Cookieorprivatemust be used for authenticated responses- CDN must not cache authenticated API responses
Exercise: Cache Testing Audit
Perform a caching audit on a web application.
Step 1: Inspect Cache Headers
Open DevTools > Network tab. Load the page and check headers for different resource types:
| Resource | Cache-Control | ETag | Max-Age | Correct? |
|---|---|---|---|---|
| HTML page | ||||
| CSS file | ||||
| JavaScript bundle | ||||
| Image | ||||
| API response (public) | ||||
| API response (authenticated) |
Step 2: Test Cache Busting
- Note the current JS/CSS file URLs (with hashes)
- Make a code change and deploy
- Verify file URLs have changed (new hashes)
- Hard refresh (Ctrl+Shift+R) should load new files
- Normal refresh should also load new files (if HTML is not cached)
Step 3: Test Stale Content
- Load a page with dynamic content (user profile, product)
- Update the content via another browser/API
- Refresh in the original browser
- Verify updated content is displayed (not stale cache)
Step 4: Cross-User Cache Test
- Log in as User A, visit profile page
- Note the API response in DevTools (User A’s data)
- Log out and log in as User B
- Visit the same profile endpoint
- Verify you see User B’s data (not User A’s cached data)
Solution: Common Caching Bugs
Bug 1: CSS cached without hash in URL After deployment, users saw the old CSS because the file URL did not change. Fix: Implement cache busting with content hashes (e.g., style.abc123.css).
Bug 2: Authenticated API response cached by CDN
CDN cached a user’s profile API response and served it to other users. Fix: Add Cache-Control: private, no-store to all authenticated endpoints.
Bug 3: Product price cached for 1 hour After updating a sale price, customers saw the old price for up to 1 hour. Fix: Reduce cache TTL for price-sensitive content or implement cache purge on price updates.
Bug 4: Stale HTML after deployment
HTML page was cached with 1-hour max-age. After deploying new JS bundles, the old HTML referenced old JS file URLs that no longer existed. Fix: Use no-cache for HTML so browsers always revalidate.
Bug 5: Browser back button shows cached sensitive data
After logging out, pressing the back button showed the previous user’s dashboard from browser cache. Fix: Add Cache-Control: no-store to all authenticated pages.
Debugging Cache Issues
Chrome DevTools
- Disable cache checkbox in Network tab (for testing without cache)
- Hard refresh (Ctrl+Shift+R) bypasses browser cache
- Check Size column: “disk cache” or “memory cache” = served from cache
- Check response headers for Cache-Control, ETag, Age
- Application > Cache Storage shows Service Worker caches
curl for Header Inspection
# Check cache headers
curl -I https://example.com/page
# Check if CDN is serving cached content (look for Age header)
curl -I https://example.com/style.css | grep -i "age\|cache-control\|etag"
Key Takeaways
- Cache testing must cover all layers: browser, CDN, and server-side
- Static assets should use long cache with content hashes for cache busting
- HTML should use no-cache to ensure users always get the latest version
- Authenticated responses must use private or no-store to prevent cross-user data leakage
- Always test cache behavior after deployments to verify users get updated content
- The browser back button can serve stale cached content — test logout flows carefully