Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Set Keys With TTL

Learn to set keys with TTL expiration in Redis. Understand time-to-live discipline, hands-on exercise, and when to choose expiration over other key management strategies.

Focus: set keys with ttl expiration

Sponsored

When you store ephemeral data in Redis — session tokens, rate-limit counters, or cached API responses — every key that lives forever becomes a liability. Left unchecked, stale keys bloat memory, degrade eviction behavior, and stack up as technical debt in your cache layer. Setting keys with a time-to-live (TTL) expiration is a fundamental Redis discipline. Without it, you're not building a cache — you're building a memory leak.

The problem this lesson solves

Redis is an in-memory data store. Every key consumes RAM, and RAM is finite. If you never expire keys, memory fills up, performance degrades, and Redis may start evicting your most important data via the configured eviction policy. For cache workloads like session stores or temporary locks, keys should self-destruct after a known lifetime. The problem is: how do you set, inspect, and manage that lifetime reliably? This lesson fills that gap, giving you the exact commands and patterns to set keys with TTL expiration, check remaining time, and avoid common pitfalls.

Core concept / mental model

Think of TTL (time-to-live) as a countdown timer attached to every key Redis supports — strings, hashes, lists, sets, sorted sets, and streams. When you set a key with expiration, you tell Redis: “Delete this key automatically after N seconds.” The mental model is like a parking meter: you pay for a certain time, and once the time runs out, the spot is freed without any manual action.

Pro tip: TTL is stored as an integer representing seconds (or milliseconds). After the timer expires, the key is removed lazily on access or actively by Redis's background expiration cycle.

Key definitions:

  • TTL: Time To Live — remaining time in seconds.
  • PTTL: Time To Live in milliseconds (more precise).
  • Expire: The point in Unix timestamp when the key will be purged.

Two approaches to set expiration

Redis gives you two clean ways to associate TTL with a key:

  1. On creation — use SET key value EX seconds or SETEX key seconds value.
  2. After creation — use EXPIRE key seconds or PEXPIRE key milliseconds on an existing key.

Both approaches achieve the same end state. The choice depends on whether you want to combine set-and-expire in one atomic call (which is generally preferred) or adjust TTL on keys that already exist.

How it works step by step

Follow the logical flow Redis executes when you set a key with TTL:

  1. You issue a SET command with an expiration flag (e.g., SET session:abc "data" EX 300).
  2. Redis stores the key's value in memory and records the absolute expire time (current Unix time + 300 seconds).
  3. A background timer runs every 100ms. On each cycle, Redis samples a subset of keys with expiry, deletes any whose expire time has passed, and records stats.
  4. When any command touches a key with expired TTL, Redis checks and deletes it proactively (lazy deletion).
  5. You can inspect remaining TTL with TTL key (returns -2 if key doesn't exist, -1 if no expiry).
  6. You can remove the expiry entirely with PERSIST key (makes it permanent).
  7. You can update the TTL at any time with another EXPIRE call — this overwrites the previous timer.

Note: TTL is not for SET alone. Every Redis data type — HSET, LPUSH, SADD, ZADD — can be expired with the same EXPIRE command after creation.

Atomic commands cheat sheet

Command shortcut Equivalent to
SET key value EX seconds SET key value then EXPIRE key seconds (but atomic)
SETEX key seconds value SET key value EX seconds (older alias)
PSETEX key ms value SET key value PX milliseconds
EXPIRE key seconds Set TTL on existing key in seconds
PEXPIRE key ms Set TTL on existing key in milliseconds
EXPIREAT key unix Set expiry at a specific Unix timestamp (seconds)
PEXPIREAT key unix_ms Set expiry at a specific Unix timestamp (ms)

Hands-on walkthrough

Let's set keys with TTL expiration in a real workflow. Open your Redis CLI (redis-cli) and follow along.

Example 1: Set and expire in one command

127.0.0.1:6379> SET cache:weather:london "sunny, 22°C" EX 60
OK
127.0.0.1:6379> TTL cache:weather:london
(integer) 57

Expected output: TTL counts down from 60. After 60 seconds, GET cache:weather:london returns (nil).

Example 2: Set TTL on an existing key

import redis

r = redis.Redis(host='localhost', port=6379, decode_responses=True)

# Create a session key
r.hset('session:abc', mapping={'user': 'alice', 'role': 'admin'})

# Set TTL to 3600 seconds (1 hour)
r.expire('session:abc', 3600)

# Check remaining time
ttl = r.ttl('session:abc')
print(f"Session expires in {ttl} seconds")
# Output: Session expires in 3599 seconds

Output: The remaining time will be close to 3600 (maybe 3599 after the command).

Example 3: Set TTL with milliseconds precision

127.0.0.1:6379> SETEX rate:limit:ip:192.168.1.1 10 "5"
OK
127.0.0.1:6379> PTTL rate:limit:ip:192.168.1.1
(integer) 9882

Here SETEX is the classic Redis command (now redundant with SET ... EX). PTTL returns milliseconds — useful for high-precision caching.

Example 4: Removing expiry

# Make a key permanent
r.persist('session:abc')
ttl = r.ttl('session:abc')
print(f"TTL after persist: {ttl}")   # Output: TTL after persist: -1

-1 means the key has no expiry.

Compare options / when to choose what

Scenario Recommended approach Why
Set a new cache entry with a lifetime SET key value EX seconds Atomic, one round-trip, no extra commands
Add expiry to an existing key (no overwrite) EXPIRE key seconds Works on any data type after creation
High-precision TTL (sub-second) SET key value PX milliseconds Avoids rounding errors from seconds
Set expiry at a specific calendar time EXPIREAT key unix_timestamp Handy for daily midnight expiry or coupon expiration
Remove TTL from a key (make permanent) PERSIST key Reverts to no expiry
Inspect remaining TTL (for debugging) TTL key / PTTL key Returns -2 if key gone, -1 if no expiry

Key insight: Prefer SET ... EX over SETEX for new Redis code — it's more explicit and symmetrical with PX. For retrofitting TTL onto existing keys, EXPIRE is the only option.

Troubleshooting & edge cases

  • TTL returns -2: Key doesn't exist or already expired. Your EXPIRE call may have been too late — or the key was deleted by another client.
  • TTL returns -1: Key exists but has no expiry. You forgot to set TTL, or you called PERSIST inadvertently.
  • Setting TTL on a key that already has TTL: EXPIRE overwrites the previous timer. There's no EXTEND command — you must calculate new total.
  • Using SET without EX or PX: Key becomes permanent. If you need expiry, always pass the flag.
  • Expiry on complex data types: Works exactly the same. But if you modify a list or hash after setting TTL, the original TTL remains — it does not reset like a sliding window.
  • Sliding expiration: Redis does not natively support sliding TTL (reset on each read). You'd need to call EXPIRE inside your application logic on every access.
  • Large TTL values: Max TTL is 9223372036854775807 seconds (technically near-infinite). Practically, anything above 2^31 seconds works fine.

Common mistake example:

127.0.0.1:6379> SET key "hello" EX 10
OK
127.0.0.1:6379> TTL key
(integer) 8
127.0.0.1:6379> GET key
"hello"
# Wait 10+ seconds...
127.0.0.1:6379> GET key
(nil)
127.0.0.1:6379> TTL key
(integer) -2

Another edge case: Using EXPIRE with a non-positive value (e.g., EXPIRE key 0) deletes the key immediately — that's a bug trap.

What you learned & what's next

You now understand how to set keys with TTL expiration — the single most important mechanism for cache invalidation and key lifecycle management in Redis. You can:

  • Explain the core idea behind TTL and how Redis manages expiration internally.
  • Apply SET ... EX, EXPIRE, PERSIST, and TTL in both CLI and Python.
  • Choose between creation-time expiry and post-hoc expiry based on your use case.
  • Troubleshoot common TTL pitfalls like -1 vs -2 returns and sliding expiration limitations.

Now you're ready to combine TTL with more advanced patterns. The next logical step is key space scanning with SCAN and expiry propagation — understanding how to efficiently inspect all keys (including those with TTL) without blocking production traffic. Move on to the next lesson to master key scanning.

Practice recap

Open your Redis CLI. Create a hash called user:profile with fields name and email. Set its TTL to 60 seconds. After 30 seconds, check TTL and verify it's decreasing. After 60 seconds, confirm the key is gone with EXISTS. Then remove the TTL before it expires using PERSIST, and verify with TTL.

Common mistakes

  • Forgetting to pass EX or PX when calling SET — key becomes permanent and memory fills up.
  • Trying to read TTL before the key is fully created — returns -2, causing confusion if you don't check existence first.
  • Assuming EXPIRE on a key with existing TTL adds time instead of overwriting — it always overwrites.
  • Using EXPIREAT with a past Unix timestamp — key gets deleted instantly (TTL becomes -2).

Variations

  1. Alternative API: EXPIREAT and PEXPIREAT for setting expiry at an absolute Unix timestamp rather than a relative TTL.
  2. For Redis 6.0+: SET ... EXAT flag to set an exact Unix timestamp directly in the SET command.
  3. Tombstone patterns: Instead of letting keys expire naturally, you can explicitly delete them with DEL — but TTL is preferred for automated cleanup.

Real-world use cases

  • Session token TTL (e.g., 1 hour after creation) — expire automatically to force re-login.
  • Rate-limiting counters with TTL (e.g., 10 requests per minute) — key self-destructs after the window closes.
  • Cached API responses (e.g., weather or pricing data) — TTL set to 5 minutes; stale data disappears without manual cleanup.

Key takeaways

  • TTL is a countdown timer — set it at key creation with SET ... EX/EX or after with EXPIRE.
  • Use PTTL for millisecond precision and EXPIREAT for absolute Unix timestamp expiry.
  • TTL returns -1 for permanent keys and -2 for non-existent or already expired keys.
  • EXPIRE on a key with TTL overwrites the previous timer — it never extends.
  • Redis does not provide built-in sliding TTL — implement it in application code if needed.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.