Cache Key Design

A cache key must uniquely and deterministically identify the data whose validity is being managed. Good key design makes cache reads consistent and invalidation precise without accidentally mixing different data.

A cache key is the identifier used to store and retrieve a cached value. For a Java backend, it is commonly represented as a `String`, although the cache library determines the exact key type and storage format.

The key should contain every input that can change the cached result. For example, a user-specific response might use `user:42:profile`, while a product lookup might use `product:123`. If two requests can produce different results, their keys should normally differ.

Keys should be deterministic: the same logical request should produce the same key every time. Avoid including values that change between identical requests, such as timestamps or random identifiers, unless that changing value is intentionally part of the cached data's identity.

Cache key design is closely connected to invalidation. A predictable namespace such as `user:42:profile` makes it easier to invalidate exactly one entry or a related group of entries. Including a cache version or namespace can also allow a broad logical invalidation by changing the version used to construct keys.

Keys should also avoid collisions. Two unrelated data types should not accidentally map to the same key, so prefixes or namespaces such as `user:`, `product:`, and `order:` are useful conventions.

Key points

Interview questions

What makes a good cache key?

A good cache key is unique for the logical data being cached and deterministic across equivalent requests. It should include all inputs that affect the result. A clear namespace or prefix helps prevent collisions between different kinds of data. The format should also make invalidation understandable and manageable.

How would you design a key for a user-specific API response?

I would include the resource type and the user identifier, for example `user:42:profile`. If the response also depends on another parameter, such as locale, I would include that parameter as well. The important rule is that requests producing different cacheable results should not share a key. The format should remain stable and easy to understand.

What bug can occur when a cache key does not include all relevant inputs?

Different requests can map to the same cache entry even though they require different results. The first request may populate the entry, and later requests can incorrectly receive that value. This is a cache correctness problem rather than merely a performance issue. The fix is to include the missing result-affecting inputs in the key or otherwise separate the cached entries.

How can cache key design help with invalidation?

A structured key gives the application a predictable way to identify related entries. For example, keys beginning with `user:42:` can represent several cached resources belonging to one user. A versioned namespace can also make older entries logically obsolete without finding every individual key immediately. The exact invalidation mechanism depends on the cache implementation, because not every cache supports efficient prefix-based deletion.

What is the difference between a deterministic key and a unique key?

A deterministic key is produced consistently from the same logical inputs, so equivalent requests generate the same identifier. Uniqueness means distinct logical cached data does not unintentionally share that identifier. A key can be deterministic but still poorly designed if different inputs produce the same result. Good cache keys aim for both stable generation and appropriate separation of data.