Redis Keyspace Notifications let you tap into the flow of data changes in your Redis instance, allowing you to react to events like key expiration, deletion, or modification.

Let’s watch Redis Keyspace Notifications in action. Imagine a simple Redis setup where we’re tracking user sessions. We want to know when a session expires so we can clean up associated data.

# Start a redis-cli session
redis-cli

# Enable keyspace notifications. We'll cover why these specific flags are chosen later.
CONFIG SET notify-keyspace-events AK$l 

# Set a key with an expiration time of 10 seconds
SET user:123:session "active" EX 10

# In another terminal, subscribe to the notification channel
redis-cli
SUBSCRIBE __keyspace@0__:expired

Now, if you go back to the first redis-cli session and wait for 10 seconds, you’ll see the following output in the second redis-cli session:

Reading messages... (press CTRL-C to quit)
1) "subscribe"
2) "__keyspace@0__:expired"
3) (integer) 1
1) "message"
2) "__keyspace@0__:expired"
3) "del"

This shows that when the user:123:session key expired, Redis sent a del event to the __keyspace@0__:expired channel.

The fundamental problem Keyspace Notifications solve is enabling asynchronous, event-driven architectures on top of Redis. Without them, you’d have to constantly poll Redis for changes, which is inefficient and scales poorly. With notifications, Redis tells you when something happens, allowing your applications to react in real-time.

Internally, Redis maintains a list of subscribers for specific event channels. When an event occurs that matches a subscribed pattern, Redis pushes the event details to all relevant subscribers. This is done efficiently without blocking the Redis server’s main event loop.

The CONFIG SET notify-keyspace-events AK$l command is the key to unlocking this functionality. Let’s break down those flags:

  • K: This flag enables keyspace notifications. Without it, nothing else matters.
  • A: This flag enables generic commands. This means events for commands like SET, DEL, INCR, etc., will be sent.
  • K: This flag enables keyspace events. This is what we used in the example to catch expired keys. It covers events like expired, evicted, keyevent.
  • $: This flag enables string events. This includes events related to operations on string values.
  • l: This flag enables list events. This includes events for LPUSH, RPUSH, LPOP, RPOP, etc.

The full set of flags are:

  • K: Keyspace notifications ON (must be set for any other event notification).
  • E: Key-event notifications ON.
  • g: Generic command notifications ON.
  • A: All of the above.
  • $: String command notifications.
  • l: List command notifications.
  • z: Sorted set command notifications.
  • h: Hash command notifications.
  • c: Set command notifications.
  • b: Bitfield command notifications.

You can combine these flags. For instance, g$l would enable generic, string, and list command notifications. AKE$lzhc is equivalent to A. The crucial part is that K must be present for any event notifications to be sent. If you only set g, you’ll get notifications for all commands, but not specific event types like expired.

The channels themselves are structured. __keyspace@<db>__:<keyname> notifies about events on a specific key within a specific database. __keyevent@<db>__:<eventname> notifies about a specific event type across all keys in a database. In our example, __keyspace@0__:expired subscribes to expired events on keys in database 0. If you wanted to subscribe to all key events in database 0, you’d use __keyevent@0__:all. However, the all is not a literal flag, you’d specify the event name like __keyevent@0__:expired.

The most surprising thing about keyspace notifications is that the DEL event is sent not only when you explicitly DEL a key, but also when a key expires or is evicted. This means you can use a single __keyspace@0__:del subscription to catch both explicit deletions and automatic expirations, simplifying your cleanup logic.

The SUBSCRIBE command itself is a blocking operation on the client side. While the Redis server efficiently handles sending notifications, your client needs to be in a listening state. This is why you typically run SUBSCRIBE in a dedicated background thread or process.

Once you’ve enabled notifications, the next logical step is to integrate this into your application logic, perhaps by processing these events in a separate worker queue to decouple your core application from the event handling.

Want structured learning?

Take the full Redis course →