Redis TTL Jitter and How It Can Help Prevent a Cache Avalanche 🚀

Learn how adding randomness to Redis expiration times can reduce synchronized cache expirations and protect downstream services from traffic spikes.
The setup: A cache without expiration
We were storing data from another system in Redis to make reads faster, but the keys had no expiration time. As a result, the cache kept growing instead of eventually clearing out old entries.
The task: Add a TTL
The task was to set a two-week time to live (TTL) for the cached data. A fixed expiration might look like this with the node-redis API:
await redis.set('mykey', value, { EX: 14 * 24 * 60 * 60 })
Check the command syntax for your Redis client, since clients expose different APIs.
The problem: Synchronized expirations
If many keys are created around the same time and all receive the same fixed TTL, they can expire in a short window together. Requests for those values then miss the cache and return to the source system. That sudden increase in work can contribute to a cache avalanche and put pressure on the backend.
The solution: Add jitter
Jitter adds a random amount of time to each key's expiration so the keys do not all expire together. For example, to spread expirations across 14 to 16 days:
const secondsPerDay = 24 * 60 * 60
const baseTTL = 14 * secondsPerDay
const jitter = Math.floor(Math.random() * (2 * secondsPerDay))
const ttl = baseTTL + jitter
await redis.set('mykey', value, { EX: ttl })
Each key now expires at a slightly different time. The spread can reduce synchronized cache misses, though the right range depends on the data and how quickly it can be refreshed.
Why it matters
Without jitter, a large group of keys can expire close together and send a burst of requests to the source system. With jitter, those expirations are distributed over a longer period, which can smooth the load.
Jitter does not replace capacity planning, cache refresh strategies, or protection against individual hot keys, but it is a small technique that can help avoid synchronized expiration spikes.
Final thoughts
Choose a TTL based on how fresh the data needs to be, then consider adding a suitable amount of jitter when many keys are created together. Test the range against your workload so expiration behavior stays within your freshness requirements.