Caching avoids repeating expensive work, a slow database query, a costly computation, by storing the result and serving it again for subsequent requests. This lesson covers the main caching layers available to an Express app.
Where Caching Can Happen
Caching can live at several layers: in application memory (fast, but per-process and lost on restart), in a shared store like Redis (survives restarts, shared across instances), or at the HTTP layer via response headers (letting browsers and CDNs skip requesting your server at all).
The right layer depends on how expensive the underlying operation is, how often the data changes, and whether multiple server instances need to share the same cached value.
EX: 3600 sets a time-to-live (in seconds) so cached data expires automatically after an hour.
Redis is shared across server instances, unlike an in-process Map.
Cache keys should be specific enough to avoid collisions between unrelated data.
Always define an eviction/expiration strategy, unbounded caches eventually exhaust memory.
Caching Strategies Cheatsheet
A comparison of caching approaches for different needs.
Approach
Shared Across Instances?
Survives Restart?
Best For
In-memory (Map)
No
No
Single-instance apps, short-lived data
Redis
Yes
Yes
Multi-instance apps, shared cached data
HTTP cache headers
N/A (client/CDN-side)
N/A
Static or rarely-changing public responses
CDN caching
Yes (edge network)
Yes
Public, cacheable API/content responses
HTTP Cache Headers
For public, non-personalized responses, HTTP cache headers let browsers and CDNs skip contacting your server entirely for repeat requests, the fastest possible cache: no request at all.
Never apply public caching to personalized or authenticated responses, doing so can leak one user's data to another.
Cache Invalidation
The hardest part of caching is knowing when to remove or refresh a cached value once the underlying data changes. A common pattern invalidates (deletes) the relevant cache key immediately after any write to that data.
Caching personalized or authenticated data with public HTTP cache headers, leaking data between users.
Never invalidating a cache after the underlying data changes, serving stale results indefinitely.
Using an in-process cache for data that needs to be consistent across multiple server instances.
Caching everything with no expiration, letting memory usage grow without bound.
Key Takeaways
Caching can live in application memory, a shared store like Redis, or the HTTP layer itself.
Redis is required when multiple server instances need to share the same cached data.
HTTP cache headers let browsers and CDNs skip hitting your server entirely for cacheable responses.
Every cache needs a clear invalidation or expiration strategy to avoid serving stale data.
Pro Tip
Always set an expiration (EX in Redis, max-age in HTTP headers) on every cache entry, even a long one, an unbounded cache with no invalidation plan quietly turns into a source of stale-data bugs.
You now understand caching strategies. Next, learn how to structure logging in the Logging lesson.