Automatic Cache Expiration in Redis Using TTL and Eviction Policies
Use Redis TTL (EX/PX) together with a volatile eviction policy to automatically expire stale cache entries and keep memory usage predictable.
16 Mar 2026, 16:43 UTC

The problem: stale cache and memory pressure
Applications that store session data, rendered page fragments, or rate‑limit counters in Redis often forget to clean them up. Over time the dataset grows until the instance hits its maxmemory limit and starts evicting keys arbitrarily, or the process runs out of memory entirely. Manual purge scripts add operational complexity and can miss edge cases.
How Redis TTL works
Redis lets you attach a time‑to‑live (TTL) to any key. The server stores an absolute expiry timestamp (epoch milliseconds) and a background thread removes the key once that moment passes. You set the TTL at write time with EX (seconds) or PX (milliseconds), or later with EXPIRE/PEXPIRE. The removal is guaranteed eventually; it is not dependent on client requests.
Choosing an eviction policy
When maxmemory is reached Redis must free space. The maxmemory-policy setting decides which keys are candidates. Common choices:
- volatile‑lru – evicts only keys that have an expiry set, preferring the least recently used.
- allkeys‑lru – evicts any key, regardless of TTL.
- volatile‑ttl – evicts the key with the shortest remaining TTL.
If you rely on TTL for true expiration, prefer a volatile‑* policy so that keys without an expiry are never removed prematurely.
Worked example: session key with a 5‑minute TTL
Assume you run redis-cli against a local instance (no special privileges required). The following commands create a JSON‑encoded session that disappears after 300 seconds.
# Set the key with a 5‑minute TTL
SET user:1234 '{"name":"Bob","role":"admin"}' EX 300
# Verify the remaining TTL (should be ≤300)
TTL user:1234
# Wait a few seconds and check again
TTL user:1234
# After 300 seconds the key is gone; TTL returns -2
TTL user:1234
You can also set the expiry after the fact:
SET user:5678 '{"name":"Alice"}'
EXPIRE user:5678 600 # 10 minutes
Trade‑offs and limits
- Too short a TTL – useful data may be evicted before the next request, causing cache misses and extra load on the primary store.
- Too long a TTL – memory is held longer than necessary; under memory pressure the eviction policy may still drop the key early.
- High‑frequency EXPIRE updates – repeatedly refreshing a key’s TTL (e.g., on every request) adds command overhead. Redis 6+ includes a lazy expiration timer that reduces this cost, but the command still traverses the event loop.
- Milliseconds vs seconds –
PXexpects milliseconds; mixingEXandPXon the same key replaces the previous expiry, so be consistent.
Verifying the behavior
Run these checks in the same redis-cli session:
INFO memory– noteused_memorybefore and after the TTL expires; it should drop.SLOWLOG GET 10– look forEXPIREorPEXPIREentries if you are updating TTLs often.MONITOR(use sparingly on production) – you will see the background deletion as aDELcommand issued by the server.
If TTL <key> returns -2, the key no longer exists. A value of -1 means the key exists but has no expiry.
Closing checklist
- Set
maxmemoryand avolatile‑lru(orvolatile‑ttl) policy for caches that must honor TTL. - Choose TTL values based on data volatility: session tokens ≈ 15‑30 min, rendered fragments ≈ 5‑10 min, rate‑limit counters ≈ 1‑2 min.
- Prefer
SET … EXat write time over separateEXPIREcalls to reduce round‑trips. - Monitor
INFO memoryandSLOWLOGafter deployment to confirm that expired keys free memory and that TTL updates aren’t a hot path.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.