API Caching Strategies: From HTTP Cache to Redis
API Caching Strategies: From HTTP Cache to Redis
Caching is the most impactful performance optimization for APIs. A cache hit avoids database queries, computation, and network round-trips. The challenge isn't adding caching — it's invalidating caches correctly. There are three layers of caching for APIs, each serving different needs.
Layer 1: HTTP Caching
Cache-Control Headers
Cache-Control: public, max-age=3600, stale-while-revalidate=60
| Directive | Meaning |
|---|---|
public | Any cache (CDN, browser, proxy) can store |
private | Only the client (browser) can cache |
no-cache | Must revalidate before using cached version |
no-store | Don't cache at all (sensitive data) |
max-age=3600 | Cache for 3600 seconds (1 hour) |
stale-while-revalidate=60 | Serve stale content while revalidating in background |
must-revalidate | Cache must not use stale content after expiry |
ETag for Conditional Requests
# First request
GET /api/products/123
→ 200 OK
ETag: "abc123"
# Subsequent request
GET /api/products/123
If-None-Match: "abc123"
→ 304 Not Modified (no body, save bandwidth)
ETags enable conditional requests — the server only sends the response body if the content changed. Saves bandwidth without serving stale data.
What to Cache at HTTP Level
| Endpoint Type | Cache Strategy |
|---|---|
| Static reference data | public, max-age=86400 (24h) |
| Product listings | public, max-age=300, stale-while-revalidate=60 (5min) |
| User-specific data | private, max-age=60 (1min) |
| Search results | public, max-age=60 (1min) |
| Real-time data | no-store or max-age=0 |
| Sensitive data | no-store, private |
Layer 2: CDN Caching
CDNs cache responses at edge locations worldwide. Requests are served from the nearest edge node without hitting your origin server.
CDN Cache Keys
By default, CDNs cache by URL. For APIs, you may need to cache by additional factors:
Cache key = URL + Accept header + Authorization (for per-user caching)
Use Vary header to tell CDNs which request headers affect the response:
Vary: Accept, Accept-Encoding, Authorization
Surrogate Keys (Cache Tags)
Tag cached responses so you can invalidate groups of related content:
Surrogate-Key: product-123 category-electronics user-456
Invalidate all products in a category: PURGE Surrogate-Key: category-electronics
Fastly and Cloudflare support surrogate keys for instant selective purging.
Layer 3: Application Cache (Redis)
For data that changes frequently or requires computation, cache at the application level.
Cache-Aside Pattern
1. Check Redis for key
2. Cache hit → return cached data
3. Cache miss → query database
4. Store result in Redis with TTL
5. Return data
Common Cached Data
| Data | TTL | Invalidation |
|---|---|---|
| API rate limit counters | 1 minute (sliding window) | TTL |
| Session data | 30 minutes | On logout |
| User profile | 5 minutes | On profile update |
| Search results | 1 minute | TTL |
| Computed aggregations | 15 minutes | TTL + event |
| Feature flags | 30 seconds | On flag update |
Cache Invalidation
The two hardest problems in computer science: cache invalidation and naming things.
Strategies
1. TTL-based (Time-to-Live) Set an expiration. Simple, predictable, eventually consistent.
2. Event-based invalidation When data changes, publish an event that invalidates the cache.
User updated → delete cache key "user:123"
3. Write-through Update cache at the same time as the database. Cache is always fresh.
4. Cache versioning Include a version in the cache key. New version = new key = fresh cache.
cache_key = "user:123:v5"
The Stale Content Problem
Sometimes serving slightly stale data is better than waiting for fresh data. Use stale-while-revalidate in HTTP caching and background refresh in application caching.
Common Mistakes
| Mistake | Impact | Fix |
|---|---|---|
| Caching authenticated responses publicly | Data leak between users | Cache-Control: private for user data |
| No Vary header | CDN serves wrong response | Add Vary for all relevant headers |
| Cache key too broad | Low hit rate | Include relevant query parameters |
| Cache key too narrow | Cache duplication | Normalize query parameters |
| No TTL on application cache | Stale data forever | Always set TTL |
| Caching errors | Persistent failures | Don't cache 4xx/5xx responses |
Optimizing API performance? Explore caching tools and API best practices on APIScout — comparisons, guides, and developer resources.