All templates
Sequence template

Cache invalidation sequence

Client, application, cache, and database coordinating fresh data.

Cache invalidation is famously one of the hardest problems in computer science. This sequence diagram shows why it's hard and what a correct invalidation strategy looks like: reads hit the cache on success, but every write must invalidate the key so the next read fetches fresh data from the database. The diagram also shows the two paths — a cache hit that avoids a database query entirely, and a cache miss that pays the cost of the database call but still updates the cache for the next client.

Missing the invalidation step is how teams ship stale-data bugs. The client makes a write, the write succeeds, the cache still holds the old value, and the next reader gets the old data and thinks nothing is wrong. This diagram makes that risk visible and shows exactly where the DEL or INVALIDATE call belongs.

When to use this template

  • Cache design reviews — sketch what data goes into the cache, when it expires, and which write paths must invalidate it before you build it.
  • Incident postmortems — when stale data reaches customers, this diagram helps explain where the invalidation broke and what the fix should be.
  • API documentation — show clients the ETag or cache-control headers they'll receive, so they understand when data is fresh vs stale.

How to adapt it

Extend the sequence to match your caching topology:

  • Add a second cache layer (local in-process cache, then Redis) if you have one, showing validation at each level.
  • Insert a publish-subscribe step after the database update, showing an event that triggers invalidation across multiple services.
  • Annotate the cache TTL value on the SET message so the expiry policy is documented where developers read it.

Visual edits regenerate clean Mermaid code, so you can turn this template into your team's actual caching architecture by just editing lifelines and message labels in the editor.

Mermaid code

Copy it anywhere Mermaid is supported — GitHub, Notion, or your docs.

sequenceDiagram
    actor Client
    participant App
    participant Cache
    participant DB as Database

    Client->>App: GET /user/123
    App->>Cache: Check cache key user:123
    alt Cache hit
        Cache-->>App: Return cached value
        App-->>Client: 200 OK (from cache)
    else Cache miss
        App->>DB: SELECT * FROM users WHERE id=123
        DB-->>App: User record
        App->>Cache: SET user:123 value EX 3600
        Cache-->>App: OK
        App-->>Client: 200 OK
    end
    Client->>App: PATCH /user/123 (update email)
    App->>DB: UPDATE users SET email=? WHERE id=123
    DB-->>App: 1 row updated
    App->>Cache: DEL user:123
    Cache-->>App: Key deleted
    App-->>Client: 200 OK

Frequently asked questions

What is cache invalidation and why is it hard?
Cache invalidation means ensuring the cached copy of data is deleted or refreshed after the source changes. It's hard because a stale cache silently serves wrong data — the client gets the old value, doesn't realize it's wrong, and may take bad actions based on it. This diagram shows the two main strategies: TTL (expiry after N seconds) and active invalidation (delete when the source updates).
Should I use TTL or active invalidation?
Use TTL for read-heavy data that can tolerate brief staleness — user profiles, product catalogs. Use active invalidation for critical state like shopping carts or payment records, where a 10-second stale cache is unacceptable. Most production systems combine both: set a TTL as a safety net, and actively invalidate on writes so the cache stays fresh.
What happens if my cache key gets out of sync with the database?
Clients start seeing stale data and reporting inconsistencies. The bug is invisible until you grep your cache logs or run a consistency check against the database. This is why the invalidation step after every write is non-negotiable — forget it once and you'll find out the hard way in production.
How do I handle cache invalidation across multiple services?
Publish a cache-invalidation event (e.g., via Kafka or a message queue) when a write happens, so all services listening on that topic can invalidate their local caches. Alternatively, invalidate at a central cache layer (Redis) and have all services read through it. The sequence diagram method works within a single service; at scale, you need event-driven or distributed cache strategies.

Related templates