Redis Expiry and TTL
Every key in Redis can carry an expiry — a countdown timer that deletes the key automatically when time runs out. This feature keeps Redis from filling up with stale data and removes the need to write cleanup jobs. You set the expiry when you create a key, or attach it afterward.
The Parking Ticket Analogy
A parking ticket is valid for two hours. When the time expires, the ticket becomes invalid and the parking space opens up. You do not need anyone to manually cancel the ticket — time does that work. A Redis key with an expiry works the same way.
Key created at 10:00 AM with a 2-hour expiry:
10:00 AM │ SET otp:user99 "847261" EX 7200
│
│ ┌──────────────────────────┐
│ │ Key: otp:user99 │
│ │ Value: "847261" │
│ │ Expires at: 12:00 PM │
│ └──────────────────────────┘
│
11:00 AM │ GET otp:user99 → "847261" ✓ (still valid)
│
12:01 PM │ GET otp:user99 → (nil) ✗ (expired, auto-deleted)
Setting Expiry at Creation Time
EX sets expiry in seconds: SET session:abc123 "user:1001" EX 1800 (expires in 30 minutes = 1800 seconds) PX sets expiry in milliseconds: SET rate:limit:ip1 "1" PX 60000 (expires in 60 seconds = 60000 milliseconds) EXAT sets expiry as a Unix timestamp (specific point in time): SET promo:flash "DEAL50" EXAT 1711929600 (expires at that exact Unix timestamp)
Attaching Expiry to an Existing Key
127.0.0.1:6379> SET token "xyz789" OK 127.0.0.1:6379> EXPIRE token 300 (integer) 1 ← expiry set (300 seconds = 5 minutes) To set expiry with a specific Unix timestamp on an existing key: 127.0.0.1:6379> EXPIREAT token 1711929600 (integer) 1
Checking Remaining Lifetime with TTL
TTL returns time remaining in seconds. PTTL returns time remaining in milliseconds. 127.0.0.1:6379> TTL token (integer) 287 ← 287 seconds left 127.0.0.1:6379> TTL no_expiry_key (integer) -1 ← -1 means no expiry set (lives forever) 127.0.0.1:6379> TTL deleted_key (integer) -2 ← -2 means key does not exist
Removing Expiry Without Deleting the Key
127.0.0.1:6379> PERSIST token (integer) 1 ← expiry removed; key now lives indefinitely 127.0.0.1:6379> TTL token (integer) -1 ← confirms no expiry
How Redis Deletes Expired Keys (Under the Hood)
Redis uses two strategies to clean up expired keys. Understanding both explains why a key disappears exactly when you access it, even if Redis has not cleaned it yet.
Strategy 1: Lazy Expiry
Redis does NOT scan for expired keys constantly.
When you GET a key, Redis first checks its expiry.
If expired → Redis deletes it right then and returns (nil).
GET expired_key
│
▼
Redis checks: is this key expired?
│
YES → delete now → return (nil)
NO → return value
Strategy 2: Active Expiry (Background Sweep)
Every 100 milliseconds, Redis samples ~20 random keys
that have an expiry set, deletes the expired ones,
and repeats if more than 25% were expired.
This prevents expired keys from sitting in memory
for too long even if nobody reads them.
Practical Patterns
One-Time Password (OTP)
User requests OTP. Server generates "481923". SET otp:user:1001 "481923" EX 300 ← valid for 5 minutes User submits OTP: GET otp:user:1001 → "481923" if still valid → (nil) if expired (OTP rejected automatically) After correct submission, delete it immediately: DEL otp:user:1001
Rate Limiting (Requests Per Minute)
Each IP gets a counter that resets every 60 seconds: INCR rate:192.168.1.5 EXPIRE rate:192.168.1.5 60 ← reset after 1 minute On each request: count = INCR rate:192.168.1.5 if count == 1: EXPIRE rate:192.168.1.5 60 if count > 100: block the request After 60 seconds, Redis deletes the key. Next request starts a fresh counter from 1.
Sliding Cache with Refresh
Cache a user's dashboard data for 10 minutes.
Each time the user opens the dashboard, refresh the timer.
SET dashboard:user:55 "..." EX 600
Each visit:
GET dashboard:user:55
if found: EXPIRE dashboard:user:55 600 ← slide the window
if not found: rebuild + SET with EX 600
Key Points
- Use EX (seconds) or PX (milliseconds) with SET to create a key that auto-deletes.
- EXPIRE attaches a timer to an already-existing key.
- TTL shows remaining seconds; -1 means no expiry; -2 means the key is gone.
- PERSIST removes the expiry, making the key permanent again.
- Redis uses lazy deletion (on access) and periodic sampling to clean expired keys efficiently.
