Redis Caching: The Cache-Aside Pattern

Cache-aside is the most common Redis caching pattern: check the cache first, fall back to the database on a miss, store the result with a TTL, and invalidate it on writes. Here's how it works and how to implement it.

Backend Engineerpythonfastapiredis

When to reach for a cache

If the same data is read far more often than it changes - a product page, a user profile, a config blob - and the query is expensive, a cache turns a 300ms database round-trip into a sub-millisecond Redis lookup. The standard pattern is cache-aside (a.k.a. lazy loading).

How cache-aside works

  1. Read: look in Redis first. Hit -> return it. Miss -> query the database, store the result in Redis with a TTL, return it.
  2. Write: update the database, then delete (invalidate) the cache key so the next read repopulates it.

Implementation (Python + Redis)

import json, redis
r = redis.Redis(host="localhost", port=6379, decode_responses=True)
CACHE_TTL = 30  # seconds

def get_product(product_id: int) -> dict:
    key = f"product:{product_id}"
    cached = r.get(key)
    if cached:                         # cache hit
        return json.loads(cached)
    product = query_product_from_db(product_id)   # cache miss -> DB
    r.setex(key, CACHE_TTL, json.dumps(product))  # store with TTL
    return product

def update_product(product_id: int, data: dict):
    save_product_to_db(product_id, data)
    r.delete(f"product:{product_id}")  # invalidate so next read is fresh

The decisions that actually matter

Cache-aside vs other patterns

Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.

Try it in a workspace →

What you'll practice

FAQ

What is the cache-aside pattern?

The app checks Redis first; on a miss it reads the database, stores the result in Redis with a TTL, and returns it. On writes it deletes the key so the next read repopulates fresh data.

How do I keep a Redis cache from going stale?

Invalidate (delete) the key whenever the underlying data changes, and always set a TTL as a backstop so stale data self-heals even if an invalidation is missed.

Should I update the cache or delete it on a write?

Delete it. Re-deriving the value on the next read is simpler than updating in place and avoids race conditions between concurrent writers.

What are the main caching strategies?

There are five common ones. Cache-aside (lazy loading) - the app manages the cache, used here. Read-through - the cache loads from the DB itself on a miss. Write-through - writes go to cache and DB together. Write-behind (write-back) - writes hit the cache and flush to the DB later. Refresh-ahead - the cache refreshes hot keys before they expire. Cache-aside is the most common.

What is the difference between LRU and TTL?

TTL (time to live) expires a key after a set time, so stale data self-heals. LRU (least recently used) is an eviction policy - when memory is full, Redis drops the least-recently-used keys to make room. You typically use both: a TTL per key plus an LRU eviction policy (maxmemory-policy allkeys-lru).

Keep learning

Return the Correct HTTP Status CodeBackend projectRepair Broken API PaginationBackend projectAdd CORS Middleware to an Express APIBackend projectBackend roadmapStep by step to hiredBackend interview questionsSTAR answersAll Backend projectsProjects hub

Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.

Open the workspace →