5 API Caching Strategies That Will 10x Your Response Times
Slow APIs kill user experience. If your endpoints are hitting the database on every single request, you're leaving massive performance gains on the table.
Here are 5 caching strategies you can implement today — from simplest to most powerful.
1. HTTP Cache Headers (The Free Win)
The easiest caching strategy requires zero infrastructure changes. Just set the right response headers:
app.get('/api/products', (req, res) => {
// Cache for 5 minutes in browser, 10 minutes in CDN
res.set('Cache-Control', 'public, max-age=300, s-maxage=600')
res.set('ETag', generateETag(data))
res.json(data)
})
Key headers:
-
Cache-Control: Controls who caches and for how long -
ETag: Enables conditional requests (304 Not Modified) -
Vary: Tells caches which request headers affect the response
Best for: Public, read-heavy endpoints like product listings or blog posts.
2. In-Memory Caching (The Quick Fix)
For single-server setups, an in-memory cache like node-cache is dead simple:
import NodeCache from 'node-cache';
const cache = new NodeCache({ stdTTL: 120 }); // 2 min default
app.get('/api/stats', async (req, res) => {
const cached = cache.get('stats')
if (cached) return res.json(cached)
const stats = await db.getExpensiveStats()
cache.set('stats', stats)
res.json(stats)
})
Pros: Near-zero latency, no external dependencies.
Cons: Not shared across instances, lost on restart.
Best for: Expensive computations on single-server apps.
3. Redis Caching (The Industry Standard)
When you need shared caching across multiple servers, Redis is the go-to:
import Redis from 'ioredis';
const redis = new Redis();
async function cachedQuery(key, ttl, queryFn) {
const cached = await redis.get(key)
if (cached) return JSON.parse(cached)
const result = await queryFn()
await redis.setex(key, ttl, JSON.stringify(result))
return result
}
// Usage
app.get('/api/users/:id', async (req, res) => {
const user = await cachedQuery(
`user:${req.params.id}`,
300,
() => db.users.findById(req.params.id)
)
res.json(user)
})
Pro tip: Use a cache-aside pattern with invalidation on writes:
app.put('/api/users/:id', async (req, res) => {
const user = await db.users.update(req.params.id, req.body)
await redis.del(`user:${req.params.id}`) // Invalidate
res.json(user)
})
Best for: Multi-instance deployments, session data, frequently accessed records.
4. Edge Caching / CDN (The Global Boost)
Push your API responses to the edge using Cloudflare Workers, Vercel Edge, or AWS CloudFront:
// Cloudflare Worker example
export default {
async fetch(request, env) {
const cache = caches.default
let response = await cache.match(request)
if (!response) {
response = await fetch(request)
response = new Response(response.body, response)
response.headers.set('Cache-Control', 's-maxage=600')
await cache.put(request, response.clone())
}
return response
}
}
This serves responses from data centers closest to users — often cutting latency from 200ms to under 20ms.
Best for: Global APIs, public data, read-heavy workloads.
5. Request Deduplication (The Hidden Gem)
When multiple users request the same data simultaneously, don't hit the database N times. Deduplicate in-flight requests:
const inFlight = new Map()
async function deduped(key, queryFn) {
if (inFlight.has(key)) return inFlight.get(key)
const promise = queryFn().finally(() => inFlight.delete(key))
inFlight.set(key, promise)
return promise
}
app.get('/api/trending', async (req, res) => {
const data = await deduped('trending', () => db.getTrending())
res.json(data)
})
This is especially powerful for endpoints that spike during traffic bursts (e.g., a product going viral).
Best for: Hot endpoints, traffic spikes, expensive queries.
Which Strategy Should You Use?
| Scenario | Strategy |
|---|---|
| Public, static-ish data | HTTP Headers + CDN |
| Single server, simple app | In-memory cache |
| Multi-server production | Redis |
| Global audience | Edge caching |
| Traffic spikes | Request deduplication |
The best approach? Layer them. Use HTTP headers as your first line, Redis for hot data, and edge caching for global reach. Add request deduplication on your most hammered endpoints.
Quick Wins to Start Today
-
Add
Cache-Controlheaders to your read endpoints — takes 5 minutes - Wrap your slowest query in a Redis cache with a 60s TTL
- Measure first — use your APM tool to find which endpoints actually need caching
Caching isn't premature optimization. It's the difference between a 500ms API and a 5ms API. Start with the simplest strategy that fits, and layer up as you scale.
Building APIs? 1xAPI provides ready-to-use API services so you can focus on your product instead of infrastructure.
Top comments (0)