VALKEY-NOTIFICATIONS(7)
πΈ NAME πΈ
valkey-notifications(7) β Keyspace notifications. That's the manual-name situation, folded in near the top so you're not confused, bestie. π
β¨ DESCRIPTION β¨
Keyspace notifications let clients subscribe to Pub/Sub channels so they can receive events that affect the Valkey data set in some way. It's giving "your data set is the main character and you get notifications about its drama." π
Examples of events that can be received are:
- All the commands affecting a given key.
- All the keys receiving an
LPUSHoperation. - All the keys expiring in the database
0.
β οΈ Note: Valkey Pub/Sub is fire and forget. That is, if your Pub/Sub client disconnects, and reconnects later, all the events delivered during the time the client was disconnected are lost. No cap, they do not come back. π
π¦ Type of events π¦
Keyspace notifications are implemented by sending two distinct types of events for every operation affecting the Valkey data space. For instance, a DEL operation targeting the key named mykey in database 0 will trigger the delivering of two messages, exactly equivalent to the following two PUBLISH commands:
PUBLISH __keyspace@0__:mykey del
PUBLISH __keyevent@0__:del mykey
The first channel listens to all the events targeting the key mykey and the other channel listens only to del operation events on the key mykey.
The first kind of event, with the keyspace prefix in the channel, is called a Key-space notification, while the second, with the keyevent prefix, is called a Key-event notification.
In the previous example a del event was generated for the key mykey, resulting in two messages:
- The Key-space channel receives as message the name of the event.
- The Key-event channel receives as message the name of the key.
It is possible to enable only one kind of notification in order to deliver just the subset of events we are interested in.
π Configuration π
By default, keyspace event notifications are disabled because while not very sensible, the feature uses some CPU power. Notifications are enabled using the notify-keyspace-events of valkey.conf or via the CONFIG SET.
Setting the parameter to the empty string disables notifications. In order to enable the feature a non-empty string is used, composed of multiple characters, where every character has a special meaning according to the following table:
Kβ Keyspace events, published with__keyspace@<db>__prefix.Eβ Keyevent events, published with__keyevent@<db>__prefix.gβ Generic commands (non-type specific) likeDEL,EXPIRE,RENAME, ...$β String commandslβ List commandssβ Set commandshβ Hash commandszβ Sorted set commandstβ Stream commandsdβ Module key type eventsxβ Expired events (events generated every time a key expires)eβ Evicted events (events generated when a key is evicted formaxmemory)mβ Key miss events (events generated when a key that doesn't exist is accessed)nβ New key events (Note: not included in the'A'class)Aβ Alias for"g$lshztxed", so that the"AKE"string means all the events except"m"and"n".
At least K or E should be present in the string, otherwise no event will be delivered regardless of the rest of the string.
For instance to enable just Key-space events for lists, the configuration parameter must be set to Kl, and so forth.
You can use the string KEA to enable most types of events.
π₯ Events generated by different commands π₯
Different commands generate different kind of events according to the following list.
DELgenerates adelevent for every deleted key.RENAMEgenerates two events, arename_fromevent for the source key, and arename_toevent for the destination key.MOVEgenerates two events, amove_fromevent for the source key, and amove_toevent for the destination key.COPYgenerates acopy_toevent.MIGRATEgenerates adelevent if the source key is removed.RESTOREgenerates arestoreevent for the key.EXPIREand all its variants (PEXPIRE,EXPIREAT,PEXPIREAT) generate anexpireevent when called with a positive timeout (or a future timestamp). Note that when these commands are called with a negative timeout value or timestamp in the past, the key is deleted and only adelevent is generated instead.SORTgenerates asortstoreevent whenSTOREis used to set a new key. If the resulting list is empty, and theSTOREoption is used, and there was already an existing key with that name, the result is that the key is deleted, so adelevent is generated in this condition.SETand all its variants (SETEX,SETNX,GETSET) generatesetevents. HoweverSETEXwill also generate anexpireevent.MSETgenerates a separatesetevent for every key.SETRANGEgenerates asetrangeevent.INCR,DECR,INCRBY,DECRBYcommands all generateincrbyevents.INCRBYFLOATgenerates anincrbyfloatevent.APPENDgenerates anappendevent.LPUSHandLPUSHXgenerates a singlelpushevent, even in the variadic case.RPUSHandRPUSHXgenerates a singlerpushevent, even in the variadic case.RPOPgenerates anrpopevent. Additionally adelevent is generated if the key is removed because the last element from the list was popped.LPOPgenerates anlpopevent. Additionally adelevent is generated if the key is removed because the last element from the list was popped.LINSERTgenerates anlinsertevent.LSETgenerates anlsetevent.LREMgenerates anlremevent, and additionally adelevent if the resulting list is empty and the key is removed.LTRIMgenerates anltrimevent, and additionally adelevent if the resulting list is empty and the key is removed.RPOPLPUSHandBRPOPLPUSHgenerate anrpopevent and anlpushevent. In both cases the order is guaranteed (thelpushevent will always be delivered after therpopevent). Additionally adelevent will be generated if the resulting list is zero length and the key is removed.LMOVEandBLMOVEgenerate anlpop/rpopevent (depending on thewherefromargument) and anlpush/rpushevent (depending on thewheretoargument). In both cases the order is guaranteed (thelpush/rpushevent will always be delivered after thelpop/rpopevent). Additionally adelevent will be generated if the resulting list is zero length and the key is removed.HSET,HSETNX,HMSETandHSETEXgenerate a singlehsetevent if the specified fields were added or modified.HINCRBYgenerates anhincrbyevent.HINCRBYFLOATgenerates anhincrbyfloatevent.HEXPIREand all its variants (HPEXPIRE,HPEXPIRE,HEXPIREATandHPEXPIREAT) generate a singlehexpireevent when called with a positive timeout (or a future timestamp). Note that when these commands are called with a negative timeout value or timestamp in the past, only a singlehexpiredevent is generated and if the hash object has no more items left it will be deleted and adelevent is generated as well.HSETEXandHGETEXgenerate a singlehexpireevent when called with a positive timeout (or a future timestamp). Note that when these commands are called with a negative timeout value or timestamp in the past, only a singlehexpiredevent is generated and if the hash object has no more items left it will be deleted and adelevent is generated as well.HPERSISTandHGETEX, will generate anhpersistevent if at least 1 hash field expiration time was removed.HDELgenerates a singlehdelevent, and an additionaldelevent if the resulting hash is empty and the key is removed.SADDgenerates a singlesaddevent, even in the variadic case.SREMgenerates a singlesremevent, and an additionaldelevent if the resulting set is empty and the key is removed.SMOVEgenerates ansremevent for the source key, and ansaddevent for the destination key.SPOPgenerates anspopevent, and an additionaldelevent if the resulting set is empty and the key is removed.SINTERSTORE,SUNIONSTORE,SDIFFSTOREgeneratesinterstore,sunionstore,sdiffstoreevents respectively. In the special case the resulting set is empty, and the key where the result is stored already exists, adelevent is generated since the key is removed.ZINCRgenerates azincrevent.ZADDgenerates a singlezaddevent even when multiple elements are added.ZREMgenerates a singlezremevent even when multiple elements are deleted. When the resulting sorted set is empty and the key is generated, an additionaldelevent is generated.ZREMBYSCOREgenerates a singlezrembyscoreevent. When the resulting sorted set is empty and the key is generated, an additionaldelevent is generated.ZREMBYRANKgenerates a singlezrembyrankevent. When the resulting sorted set is empty and the key is generated, an additionaldelevent is generated.ZDIFFSTORE,ZINTERSTOREandZUNIONSTORErespectively generatezdiffstore,zinterstoreandzunionstoreevents. In the special case the resulting sorted set is empty, and the key where the result is stored already exists, adelevent is generated since the key is removed.XADDgenerates anxaddevent, possibly followed by anxtrimevent when used with theMAXLENsubcommand.XDELgenerates a singlexdelevent even when multiple entries are deleted.XGROUP CREATEgenerates anxgroup-createevent.XGROUP CREATECONSUMERgenerates anxgroup-createconsumerevent.XGROUP DELCONSUMERgenerates anxgroup-delconsumerevent.XGROUP DESTROYgenerates anxgroup-destroyevent.XGROUP SETIDgenerates anxgroup-setidevent.XSETIDgenerates anxsetidevent.XTRIMgenerates anxtrimevent.PERSISTgenerates apersistevent if the expiry time associated with the key has been successfully deleted.- Every time a key with a time to live associated is removed from the data set because it expired, an
expiredevent is generated. - Every time a key is evicted from the data set in order to free memory as a result of the
maxmemorypolicy, anevictedevent is generated. - Every time a new key is added to the data set, a
newevent is generated.
IMPORTANT all the commands generate events only if the target key is really modified. For instance an SREM deleting a non-existing element from a Set will not actually change the value of the key, so no event will be generated.
If in doubt about how events are generated for a given command, the simplest thing to do is to watch yourself:
$ valkey-cli config set notify-keyspace-events KEA
$ valkey-cli --csv psubscribe '__key*__:*'
Reading messages... (press Ctrl-C to quit)
"psubscribe","__key*__:*",1
okay bestie now open another terminal (yes, a whole second one, you're that girl) and yeet some commands at the Valkey server, then just watch the events roll in like:
"pmessage","__key*__:*","__keyspace@0__:foo","set"
"pmessage","__key*__:*","__keyevent@0__:set","foo"
...
β° Timing of expired events π
Keys that have a time to live attached get expired by Valkey in two whole ways, and you need to know both:
- When the key is accessed by a command and turns out to be expired. π
- Via a background system that hunts for expired keys in the background, incrementally, so it can also sweep up the keys that never get accessed at all. π§Ή
So the expired events fire when a key is accessed and one of those two systems decides it's expired. Which means β and this is the part that gets people β there are no guarantees that the Valkey server will manage to generate the expired event at the exact moment the key's time to live hits zero. It's giving whenever, not on the dot. π
Since Valkey 9.0, hash fields can have an associated time to live too. π Hash fields get deleted when you explicitly hand them an expiration time in the past, or via that same background job that's also responsible for expiring keys. And for that exact reason, there are no guarantees that the Valkey server will be able to generate the hexpired event at the moment the hash field's time to live reaches zero either. Same energy, different data type, bestie.
Basically: expired and hexpired events are generated when the Valkey server deletes a key, not when the time to live theoretically reaches zero. So there can be a significant delay between the moment the key's time to live drops to zero and the moment the corresponding event actually shows up. Not a bug, just how it works, no cap. π
π Events in a cluster π¦
Every single node of a Valkey cluster generates events about its own subset of the keyspace, exactly as described above. Main character energy, but only over their own little corner. π
BUT β and this is the plot twist β unlike regular Pub/Sub communication in a cluster, events' notifications are not broadcasted to all nodes. Put differently: keyspace events are node-specific. πΈ
Which means if you want to receive all the keyspace events of a cluster, your clients need to subscribe to each of the nodes. Every one. Yes, all of them. Sorry bestie, that's just the vibe check. π«Ά
That's the whole page, you made it, so proud of you fr fr. π This one's from Valkey 9.0.0, dated 2025-10-21, and it lives at VALKEY-NOTIFICATIONS(7). Go forth and subscribe responsibly, icon. β¨ππ¦
π¦ where this page comes from
- fedora 44: valkey-doc 9.0.3-2.fc44 Β· CC-BY-SA-4.0
- fedora 44: valkey-doc 9.0.6-1.fc44 Β· CC-BY-SA-4.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms