Cache Key Design
Cache key design determines which requests share a cached entry. Include all result-affecting inputs and construct keys consistently so reuse is correct and predictable.
A cache key is the address used to store and retrieve a cached value. Good key design makes equivalent requests produce the same key, while requests whose results differ produce different keys.
Include every input that can change the result, such as a resource ID, tenant, locale, permissions scope, or relevant query options. If an input is omitted, one request may receive another request's cached data. This is especially important when responses vary by user or access rights.
Use a consistent representation: normalize values where appropriate, choose stable separators or structured encoding, and avoid relying on unordered data. Be careful that normalization matches the application's semantics; for example, lowercasing is only safe when the value is case-insensitive.
Keys should also be practical for the cache backend: keep them bounded in size and avoid putting secrets or sensitive personal data in them. Namespacing and version components can help separate environments, data types, or incompatible result formats and make invalidation easier.
Key points
- Include every input that can change the cached result.
- Ensure equivalent requests create identical keys and distinct results do not collide.
- Represent values unambiguously and normalize only when semantics allow it.
- Use namespaces or versions to separate data types, environments, or result formats.
- Keep keys bounded and free of secrets.
Interview questions
What makes a cache key well designed?
A cache key should uniquely represent the inputs that determine the cached result. Include any relevant identifiers and options, such as tenant, locale, or authorization scope. Make construction deterministic so equivalent inputs produce the same key. Avoid including irrelevant values, since they reduce cache reuse.
How can cache keys prevent one user's response from being served to another?
If the response depends on the authenticated user's permissions, the key must distinguish the relevant authorization context. Depending on the system, that might mean including a user ID, tenant ID, or stable permission-scope identifier. Do not assume that a URL alone identifies a response when authentication affects its contents. Also avoid placing credentials or other secrets directly in a key.
How would you build stable keys when inputs include dictionaries or optional values?
Canonicalize inputs into a stable representation before building the key. For example, sort mapping keys and normalize optional values consistently, but only normalize things such as case when the application treats them as equivalent. Encode boundaries unambiguously rather than concatenating values in a way that can produce ambiguous strings. If keys can become large, hash the canonical representation while retaining a readable namespace or prefix.
How do namespaces and key versions help with cache invalidation?
Add a namespace or version component to the key so entries from different data types, environments, or result formats do not overlap. A version bump can make old entries unreachable after a deployment changes the cached representation or its meaning. This is a form of coarse invalidation, not a replacement for expiration or targeted invalidation. The migration should account for the temporary loss of cache hits and resulting load on the backing service.