Cache invalidation is a naming problem

The hard part is not deciding when to drop a cached value. It is knowing which value you cached.

A key is a claim

Every cache key says "this data depends on exactly these inputs". If the key omits an input, the cache lies. Most stale-data bugs are a missing field in the key, not a broken expiry.

Put the inputs in the name

A key like user:42 hides the version, the locale, and the permission set. A key like user:42:v3:en:admin is ugly and honest. When an input changes, the key changes, and the old entry falls out on its own.

Expiry is a guess

A TTL says "I do not know when this goes stale, so I picked a number". That is fine as a safety net. It is not a correctness strategy. If the value must be fresh, derive the key from what makes it fresh.

Deleting is the last resort

Explicit invalidation means every writer must remember every reader. That coupling grows with the codebase and nobody updates it. Content-addressed keys need no writer to remember anything.

What this buys you

Rollbacks stop serving the wrong page. Two deploys can share a cache without fighting. And the bug report stops being "sometimes it is old", which is the report you can never reproduce.