A cache is one big shared pool of keys, so naming matters. The convention is colon-delimited
namespaces that read from general to specific: user:42:profile. Good key names
prevent collisions, make the cache easy to reason about, and let you find or clear related keys by
their shared prefix.
A naming pattern
const key = (userId: number) => `user:${userId}:profile`;
await cache.set(key(42), JSON.stringify(profile), { EX: 300 });
const cached = await cache.get(key(42)); Mirror your entity hierarchy
Structure keys to reflect the relationships in your data model. If users own posts and posts have
comments, that nesting should show up in the key: user:42:post:7:comments. A reader
can look at any key and immediately know what entity it belongs to, where it sits in the
hierarchy, and what other keys are related to it.
This also makes invalidation natural. When a user is deleted, all keys under
user:42: are candidates for eviction. When a post is updated,
user:42:post:7: keys are the scope to clear.
Why conventions help
- No collisions —
user:42andpost:42never clash, even though both end in 42 - Grouping — every key under
user:42:belongs to one user and can be cleared together - Versioning — bump a prefix (
v2:user:42:profile) to invalidate a whole shape of data at once - Shared caches — prefix by service name (
auth:,catalog:) when multiple services share a cache instance so their keys never overlap
Pick one convention and apply it everywhere. A consistent scheme is what keeps a shared cache from turning into a junk drawer.
Exercise
Redis challenge · runs in your browser
Key namespaces — organize keys with prefixes
Commands run against an in-browser Redis mock that implements the full ioredis API. Your code works identically against a real Redis instance — just swap in new Redis() from ioredis.