Commands

acl-cat

The command shows the available ACL categories if called without arguments. If a category name is given, the command shows all the Valkey commands in the specified category.

ACL categories are very useful in order to create ACL rules that include or exclude a large set of commands at once, without specifying every single command. For instance, the following rule will let the user karin perform everything but the most dangerous operations that may affect the server stability:

ACL SETUSER karin on +@all -@dangerous

We first add all the commands to the set of commands that karin is able to execute, but then we remove all the dangerous commands.

Checking for all the available categories is as simple as:

> ACL CAT
 1) "keyspace"
 2) "read"
 3) "write"
 4) "set"
 5) "sortedset"
 6) "list"
 7) "hash"
 8) "string"
 9) "bitmap"
10) "hyperloglog"
11) "geo"
12) "stream"
13) "pubsub"
14) "admin"
15) "fast"
16) "slow"
17) "blocking"
18) "dangerous"
19) "connection"
20) "transaction"
21) "scripting"

Then we may want to know what commands are part of a given category:

> ACL CAT dangerous
 1) "flushdb"
 2) "acl"
 3) "slowlog"
 4) "debug"
 5) "role"
 6) "keys"
 7) "pfselftest"
 8) "client"
 9) "bgrewriteaof"
10) "replicaof"
11) "monitor"
12) "restore-asking"
13) "latency"
14) "replconf"
15) "pfdebug"
16) "bgsave"
17) "sync"
18) "config"
19) "flushall"
20) "cluster"
21) "info"
22) "lastsave"
23) "slaveof"
24) "swapdb"
25) "module"
26) "restore"
27) "migrate"
28) "save"
29) "shutdown"
30) "psync"
31) "sort"

acl-delrole

Delete all the specified ACL roles. A role cannot be deleted while it is assigned to a user: if any of the specified roles is still held by a user, the command returns an error and no role is deleted. Use the resetroles or role= rules of ACL SETUSER to remove the role from its users first. The users holding a role are listed by ACL GETROLE.

The list of roles may include role names that do not exist, in such case no operation is performed for the non existing roles.

Examples

127.0.0.1:6379> ACL DELROLE reader
(error) ERR Role 'reader' is assigned to one or more users. Remove it from them first.
127.0.0.1:6379> ACL SETUSER alice resetroles
OK
127.0.0.1:6379> ACL DELROLE reader nosuchrole
(integer) 1

acl-deluser

Delete all the specified ACL users and terminate all the connections that are authenticated with such users. Note: the special default user cannot be removed from the system, this is the default user that every new connection is authenticated with. The list of users may include usernames that do not exist, in such case no operation is performed for the non existing users.

Examples

127.0.0.1:6379> ACL DELUSER antirez
(integer) 1

acl-digest

Return a fingerprint of the ACL rules currently in effect, as a hexadecimal string. The digest depends only on the rules in effect and not on the order the users were created in, so two servers configured alike report the same digest.

The digest covers everything ACL LIST reports: the user names, their flags, their password hashes, and their command, key and channel rules. Any change to any user changes the digest. The reply is the same size however many users are configured.

This is meant for confirming which revision of an ACL a server is running. A client that manages users through an ACL file can read the digest before and after an ACL LOAD to tell whether the file it wrote is the one now in effect. Comparing the rules themselves is impractical, because the server reports them in its own normalized form rather than the form they were written in, so a client would need its own copy of the rule parser to compare them.

Examples

127.0.0.1:6379> ACL DIGEST
"24ece0a4daea0bcb936b438ae6c9f36db76f57dfc70e00def7b2c26041c49822"
127.0.0.1:6379> ACL SETUSER alice on >alice ~key:* +get
OK
127.0.0.1:6379> ACL DIGEST
"d06ec40dd1a8e30a4babea1011d4b0daf02dbdf5de95ea18768e15f346a7d385"
127.0.0.1:6379> ACL DELUSER alice
(integer) 1
127.0.0.1:6379> ACL DIGEST
"24ece0a4daea0bcb936b438ae6c9f36db76f57dfc70e00def7b2c26041c49822"

acl-dryrun

Simulate the execution of a given command by a given user. This command can be used to test the permissions of a given user without having to enable the user or cause the side effects of running the command.

Examples

127.0.0.1:6379> ACL SETUSER VIRGINIA +SET ~*
"OK"
127.0.0.1:6379> ACL DRYRUN VIRGINIA SET foo bar
"OK"
127.0.0.1:6379> ACL DRYRUN VIRGINIA GET foo
"User VIRGINIA has no permissions to run the 'get' command"

acl-genpass

ACL users need a solid password in order to authenticate to the server without security risks. Such password does not need to be remembered by humans, but only by computers, so it can be very long and strong (unguessable by an external attacker). The ACL GENPASS command generates a password starting from /dev/urandom if available, otherwise (in systems without /dev/urandom) it uses a weaker system that is likely still better than picking a weak password by hand.

By default (if /dev/urandom is available) the password is strong and can be used for other uses in the context of an application, for instance in order to create unique session identifiers or other kind of unguessable and not colliding IDs. The password generation is also very cheap because we don't really ask /dev/urandom for bits at every execution. At startup Valkey creates a seed using /dev/urandom, then it will use SHA256 in counter mode, with HMAC-SHA256(seed,counter) as primitive, in order to create more random bytes as needed. This means that the application developer should be feel free to abuse ACL GENPASS to create as many secure pseudorandom strings as needed.

The command output is a hexadecimal representation of a binary string. By default it emits 256 bits (so 64 hex characters). The user can provide an argument in form of number of bits to emit from 1 to 1024 to change the output length. Note that the number of bits provided is always rounded to the next multiple of 4. So for instance asking for just 1 bit password will result in 4 bits to be emitted, in the form of a single hex character.

Examples

127.0.0.1:6379> ACL GENPASS
"dd721260bfe1b3d9601e7fbab36de6d04e2e67b0ef1c53de59d45950db0dd3cc"
127.0.0.1:6379> ACL GENPASS 32
"355ef3dd"
127.0.0.1:6379> ACL GENPASS 5
"90"

acl-getrole

The command returns all the rules defined for an existing ACL role, and the users that hold it. The command returns a null reply if the role does not exist.

Specifically, it lists the role's commands, key patterns, channel patterns, databases and selectors, with rules returned in the same format as the one used in the ACL SETROLE command, followed by the names of the users the role is assigned to.

Examples

127.0.0.1:6379> ACL SETROLE reader ~app:* +@read (+info)
OK
127.0.0.1:6379> ACL SETUSER alice on >alicepass role=reader
OK
127.0.0.1:6379> ACL GETROLE reader
 1) "commands"
 2) "-@all +@read"
 3) "keys"
 4) "~app:*"
 5) "channels"
 6) ""
 7) "databases"
 8) "alldbs"
 9) "selectors"
10) 1)  1) "commands"
        2) "-@all +info"
        3) "keys"
        4) ""
        5) "channels"
        6) ""
        7) "databases"
        8) "alldbs"
11) "users"
12) 1) "alice"
127.0.0.1:6379> ACL GETROLE nosuchrole
(nil)

acl-getuser

The command returns all the rules defined for an existing ACL user.

Specifically, it lists the user's ACL flags, password hashes, commands, key patterns, channel patterns (Added in version 6.2), selectors (Added in version 7.0), databases (Added in version 9.1) and roles (Added in version 9.2). Additional information may be returned in the future if more metadata is added to the user.

Command rules are always returned in the same format as the one used in the ACL SETUSER command. Before version 7.0, keys and channels were returned as an array of patterns, however in version 7.0 later they are now also returned in same format as the one used in the ACL SETUSER command. Note: This description of command rules reflects the user's effective permissions, so while it may not be identical to the set of rules used to configure the user, it is still functionally identical.

Selectors are listed in the order they were applied to the user, and include information about commands, key patterns, channel patterns, and database permissions.

Roles are listed in the order they were assigned to the user. The commands, keys, channels, databases and selectors fields only describe the user's own rules, not the permissions the user gets from its roles. Use ACL GETROLE to inspect the rules of a role, and ACL DRYRUN to check the effective permissions of a user.

Examples

Here's an example configuration for a user

127.0.0.1:6379> ACL SETUSER sample on nopass +GET allkeys &* (+SET ~key2)
"OK"
127.0.0.1:6379> ACL GETUSER sample
1) "flags"
2) 1) "on"
   2) "nopass"
3) "passwords"
4) (empty array)
5) "commands"
6) "-@all +get"
7) "keys"
8) "~*"
9) "channels"
10) "&*"
11) "databases"
12) "alldbs"
13) "selectors"
14) 1) 1) "commands"
       2) "-@all +set"
       3) "keys"
       4) "~key2"
       5) "channels"
       6) ""
       7) "databases"
       8) "alldbs"
15) "roles"
16) (empty array)

acl-help

The ACL HELP command returns a helpful text describing the different subcommands.

acl-list

The command shows the currently active ACL rules in the Valkey server. Each line in the returned array defines a different role or user. Lines starting with role describe roles and are listed first, followed by the lines starting with user. The format is the same used in the valkey.conf file or the external ACL file, so you can cut and paste what is returned by the ACL LIST command directly inside a configuration file if you wish (but make sure to check ACL SAVE). Implicit defaults may be omitted: for example, access to all databases (alldbs) is not shown, while explicit db=<dbid> and resetdbs rules are shown.

Examples

127.0.0.1:6379> ACL LIST
1) "role reader ~app:* resetchannels -@all +@read"
2) "user alice on #13dc8554575637802eec3c0117f41591a990e1a2d37160018c48c9125063838a resetchannels -@all role=reader"
3) "user antirez on #9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 ~objects:* &* +@all -@admin -@dangerous"
4) "user default on nopass ~* &* +@all"

acl-load

When Valkey is configured to use an ACL file (with the aclfile configuration option), this command will reload the ACLs from the file, replacing all the current ACL rules with the ones defined in the file. The command makes sure to have an all or nothing behavior, that is:

Examples

127.0.0.1:6379> ACL LOAD
OK
127.0.0.1:6379> ACL LOAD
(error) ERR /tmp/foo:1: Unknown command or category name in ACL...

acl-log

The command shows a list of recent ACL security events:

  1. Failures to authenticate their connections with AUTH or HELLO.
  2. Commands denied because against the current ACL rules.
  3. Commands denied because accessing keys not allowed in the current ACL rules.
  4. Commands denied because accessing Pub/Sub channels not allowed in the current ACL rules.
  5. Commands denied because accessing a database not allowed in the current ACL rules.
  6. TLS clients failing automatic authentication via certificate field because no matching user exists.

The optional argument specifies how many entries to show. By default up to ten failures are returned. The special RESET argument clears the log. Entries are displayed starting from the most recent.

Examples

127.0.0.1:6379> AUTH someuser wrongpassword
(error) WRONGPASS invalid username-password pair
> ACL LOG 1
1)  1) "count"
    2) (integer) 1
    3) "reason"
    4) "auth"
    5) "context"
    6) "toplevel"
    7) "object"
    8) "AUTH"
    9) "username"
   10) "someuser"
   11) "age-seconds"
   12) "8.038"
   13) "client-info"
   14) "id=3 addr=127.0.0.1:57275 laddr=127.0.0.1:6379 fd=8 name= age=16 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 qbuf=48 qbuf-free=16842 argv-mem=25 multi-mem=0 rbs=1024 rbp=0 obl=0 oll=0 omem=0 tot-mem=18737 events=r cmd=auth user=default redir=-1 resp=2"
   15) "entry-id"
   16) (integer) 0
   17) "timestamp-created"
   18) (integer) 1675361492408
   19) "timestamp-last-updated"
   20) (integer) 1675361492408

Each log entry is composed of the following fields:

  1. count: The number of security events detected within a 60 second period that are represented by this entry.
  2. reason: The reason that the security events were logged. One of the following:
    • command: the user has no permission to run the command.
    • key: the user has no permission to access one of the keys used by the command.
    • channel: the user has no permission to access one of the Pub/Sub channels used by the command.
    • database: the user has no permission to access one of the databases referenced by the command.
    • auth: authentication failed for the connection.
    • tls-cert: automatic authentication from a TLS certificate failed because no matching user exists.
  3. context: The context that the security events were detected in. Either toplevel, multi, lua, script, or module.
  4. object: The resource that the user had insufficient permissions to access. The value depends on reason:
    • command: the command name.
    • key: the key pattern.
    • channel: the Pub/Sub channel.
    • database: the database id, or the command name when the command implicitly accesses every database (such as FLUSHALL).
    • auth: the literal string AUTH.
    • tls-cert: the certificate that did not match any existing user.
  5. username: The username that executed the command that caused the security events or the username that had a failed authentication attempt.
  6. age-seconds: Age of the log entry in seconds.
  7. client-info: Displays the client info of a client which caused one of the security events.
  8. entry-id: The sequence number of the entry (starting at 0) since the server process started. Can also be used to check if items were “lost”, if they fell between periods.
  9. timestamp-created: A UNIX timestamp in milliseconds at the time the entry was first created.
  10. timestamp-last-updated: A UNIX timestamp in milliseconds at the time the entry was last updated.

acl-roles

The command shows a list of all the names of the currently configured roles in the Valkey ACL system.

Examples

127.0.0.1:6379> ACL ROLES
1) "ops"
2) "reader"
3) "writer"

acl-save

When Valkey is configured to use an ACL file (with the aclfile configuration option), this command will save the currently defined ACLs from the server memory to the ACL file.

Examples

127.0.0.1:6379> ACL SAVE
OK
127.0.0.1:6379> ACL SAVE
(error) ERR There was an error trying to save the ACLs. Please check the server logs for more information

acl-setrole

Create an ACL role with the specified rules or modify the rules of an existing role.

A role is a named, reusable set of permissions that can be assigned to any number of users with the role= rule of ACL SETUSER, so a policy is written once instead of being repeated in every user. See roles for more information.

If the role does not exist, the command creates it without any privilege. It then reads from left to right all the rules provided as successive arguments, setting the role ACL rules as specified. If the role already exists, the provided ACL rules are applied in addition to the rules already set, exactly as ACL SETUSER does for users. The rules are applied atomically: if any rule is invalid, the role is left unchanged.

A role accepts the command rules of ACL SETUSER, as well as selectors ((<rule list>)) and clearselectors. The rules that only make sense for a user are rejected with an error: on, off, reset, the password rules (>, <, #, !, nopass, resetpass), role= and resetroles. Roles cannot be nested.

Changes to a role take effect immediately for every user holding it. If the change removes access to Pub/Sub channels, the clients of those users that are subscribed to channels they can no longer access are disconnected.

Role names are case sensitive and may contain any printable ASCII character except for spaces, commas, quotes (" and ') and backslashes. Roles live in a namespace of their own, so a role may have the same name as a user, a command, or a category.

Note: a new role starts with access to all databases (alldbs), and to all Pub/Sub channels if acl-pubsub-default is set to allchannels, just like a new user. Since a user's own permissions and those of its roles are combined with OR logic, such a role grants those databases and channels to its users even if the user itself is restricted with resetdbs, db=<id> or resetchannels. Use db=<id> (or resetdbs) and resetchannels in the role rules to restrict the role itself. See database permissions.

Examples

127.0.0.1:6379> ACL SETROLE reader ~app:* +@read
OK
127.0.0.1:6379> ACL SETROLE ops ~* +info (+config|get)
OK
127.0.0.1:6379> ACL SETROLE reader on
(error) ERR Error in ACL SETROLE modifier 'on': Syntax error

acl-setuser

Create an ACL user with the specified rules or modify the rules of an existing user.

Manipulate Valkey ACL users interactively. If the username does not exist, the command creates the username without any privilege. It then reads from left to right all the rules provided as successive arguments, setting the user ACL rules as specified. If the user already exists, the provided ACL rules are simply applied in addition to the rules already set. For example:

ACL SETUSER virginia on allkeys +set

The above command creates a user called virginia who is active(the on rule), can access any key (allkeys rule), and can call the set command (+set rule). Then, you can use another ACL SETUSER call to modify the user rules:

ACL SETUSER virginia +get

The above rule applies the new rule to the user virginia, so other than SET, the user virginia can now also use the GET command.

ACL rules can also be grouped into multiple distinct sets of rules, called selectors. Selectors are added by wrapping the rules in parentheses and providing them just like any other rule. In order to execute a command, either the root permissions (rules defined outside of parenthesis) or any of the selectors (rules defined inside parenthesis) must match the given command. For example:

ACL SETUSER virginia on +GET allkeys (+SET ~app1*)

This sets a user with two sets of permissions, one defined on the user and one defined with a selector. The root user permissions only allow executing the get command, but can be executed on any keys. The selector then grants a secondary set of permissions: access to the SET command to be executed on any key that starts with app1. Using multiple selectors allows you to grant permissions that are different depending on what keys are being accessed.

Permissions can also be defined once in a named role, created with ACL SETROLE, and assigned to any number of users with the role= rule:

ACL SETROLE reader ~app:* +@read
ACL SETUSER virginia on >password role=reader

A user's own permissions are combined with those of its roles, so a user can add permissions on top of a role but cannot take away what a role grants.

When we want to be sure to define a user from scratch, without caring if it had previously defined rules associated, we can use the special rule reset as first rule, in order to flush all the other existing rules:

ACL SETUSER antirez reset [... other rules ...]

After resetting a user, its ACL rules revert to the default: inactive, passwordless, can't execute any command nor access any key or channel:

127.0.0.1:6379> ACL SETUSER antirez reset
OK
127.0.0.1:6379> ACL LIST
1) "user antirez off -@all"

ACL rules are either words like "on", "off", "reset", "allkeys", or are special rules that start with a special character, and are followed by another string (without any space in between), like "+SET".

The following documentation is a reference manual about the capabilities of this command, however our ACL tutorial may be a more gentle introduction to how the ACL system works in general.

ACL rules

Valkey ACL rules are split into two categories: rules that define command permissions or command rules, and rules that define the user state or user management rules. This is a list of all the supported Valkey ACL rules:

Command rules

User management rules

Examples

127.0.0.1:6379> ACL SETUSER alan allkeys +@string +@set -SADD >alanpassword
OK
127.0.0.1:6379> ACL SETUSER antirez heeyyyy
(error) ERR Error in ACL SETUSER modifier 'heeyyyy': Syntax error

Restrict a user to a subset of databases:

127.0.0.1:6379> ACL SETUSER alice on +@all ~* db=0,1 nopass
OK
127.0.0.1:6379> ACL LIST
1) "user alice on nopass ~* resetchannels db=0,1 +@all"
2) "user default on nopass ~* &* +@all"

A later db= rule replaces the previous database list:

127.0.0.1:6379> ACL SETUSER alice db=2,3
OK
127.0.0.1:6379> ACL LIST
1) "user alice on nopass ~* resetchannels db=2,3 +@all"
2) "user default on nopass ~* &* +@all"

Different selectors can grant access on different databases:

127.0.0.1:6379> ACL SETUSER bob on nopass (db=0,1 +@write +select ~*) (db=2,3 +@read +select ~*)
OK
127.0.0.1:6379> ACL LIST
1) "user bob on nopass resetchannels -@all (~* resetchannels db=0,1 -@all +@write +select) (~* resetchannels db=2,3 -@all +@read +select)"
2) "user default on nopass ~* &* +@all"

The ACL LIST output shows three sets of permissions for bob: the root permissions (-@all, with implicit alldbs) and two selectors, one for each parenthesized rule set. A command is allowed when the root permissions or any selector matches it. See selectors for more information.

acl-users

The command shows a list of all the usernames of the currently configured users in the Valkey ACL system. Roles are not included, use ACL ROLES to list them.

Examples

127.0.0.1:6379> ACL USERS
1) "anna"
2) "antirez"
3) "default"

acl-whoami

Return the username the current connection is authenticated with. New connections are authenticated with the "default" user. They can change user using AUTH.

Examples

127.0.0.1:6379> ACL WHOAMI
"default"

acl

This is a container command for Access Control List commands.

To see the list of available commands you can call ACL HELP.

append

If key already exists and is a string, this command appends the value at the end of the string. If key does not exist it is created and set as an empty string, so APPEND will be similar to SET in this special case.

Examples

127.0.0.1:6379> EXISTS mykey
(integer) 0
127.0.0.1:6379> APPEND mykey "Hello"
(integer) 5
127.0.0.1:6379> APPEND mykey " World"
(integer) 11
127.0.0.1:6379> GET mykey
"Hello World"

Pattern: Time series

The APPEND command can be used to create a very compact representation of a list of fixed-size samples, usually referred as time series. Every time a new sample arrives we can store it using the command

APPEND timeseries "fixed-size sample"

Accessing individual elements in the time series is not hard:

The limitation of this pattern is that we are forced into an append-only mode of operation, there is no way to cut the time series to a given size easily because Valkey currently lacks a command able to trim string objects. However the space efficiency of time series stored in this way is remarkable.

Hint: it is possible to switch to a different key based on the current Unix time, in this way it is possible to have just a relatively small amount of samples per key, to avoid dealing with very big keys, and to make this pattern more friendly to be distributed across many Valkey instances.

An example sampling the temperature of a sensor using fixed-size strings (using a binary format is better in real implementations).

127.0.0.1:6379> APPEND ts "0043"
(integer) 4
127.0.0.1:6379> APPEND ts "0035"
(integer) 8
127.0.0.1:6379> GETRANGE ts 0 3
"0043"
127.0.0.1:6379> GETRANGE ts 4 7
"0035"

asking

When a cluster client receives an -ASK redirect, the ASKING command is sent to the target node followed by the command which was redirected. This is normally done automatically by cluster clients.

If an -ASK redirect is received during a transaction, only one ASKING command needs to be sent to the target node before sending the complete transaction to the target node.

See ASK redirection in the Valkey Cluster Specification for details.

auth

The AUTH command authenticates the current connection using the Valkey ACL system.

The standard way to AUTH is the two-argument form:

AUTH <username> <password>

This authenticates the current connection with one of the users defined in the ACL list (see ACL SETUSER and the official ACL guide for more information).

When the single argument form of the command is used, where only the password is specified, it is assumed that the implicit username is "default".

AUTH <password>

This form authenticates against the "default" user's password set with requirepass.

If the password provided via AUTH matches the password in the configuration file, the server replies with the OK status code and starts accepting commands. Otherwise, an error is returned and the clients needs to try a new password.

Security notice

Because of the high performance nature of Valkey, it is possible to try a lot of passwords in parallel in very short time, so make sure to generate a strong and very long password so that this attack is infeasible. A good way to generate strong passwords is via the ACL GENPASS command.

bf.add

Adds a single item to a bloom filter. If the specified bloom filter does not exist, a bloom filter is created with the provided name with default properties.

To add multiple items to a bloom filter, you can use the BF.MADD or BF.INSERT commands.

To create a bloom filter with non-default properties, use the BF.INSERT or BF.RESERVE command.

Examples

127.0.0.1:6379> BF.ADD key val
(integer) 1
127.0.0.1:6379> BF.ADD key val
(integer) 0

bf.card

Returns the cardinality of a bloom filter which is the number of items that have been successfully added to it.

Examples

127.0.0.1:6379> BF.ADD key val
(integer) 1
127.0.0.1:6379> BF.CARD key
(integer) 1
127.0.0.1:6379> BF.CARD nonexistentkey
(integer) 0

bf.exists

Determines if an item has been added to the bloom filter previously.

A bloom filter has two possible responses when you check if an item exists:

Examples

127.0.0.1:6379> BF.ADD key val
(integer) 1
127.0.0.1:6379> BF.EXISTS key val
(integer) 1
127.0.0.1:6379> BF.EXISTS key nonexistent
(integer) 0

bf.info

Returns usage information and properties of a specific bloom filter.

Info Fields

For non-scaling filters, the TIGHTENING and MAXSCALEDCAPACITY fields are not applicable and will not be returned. When no optional fields are specified, all available fields for the given filter type are returned.

Examples

127.0.0.1:6379> BF.ADD key val
(integer) 1
127.0.0.1:6379> BF.INFO key
 1) Capacity
 2) (integer) 100
 3) Size
 4) (integer) 384
 5) Number of filters
 6) (integer) 1
 7) Number of items inserted
 8) (integer) 2
 9) Error rate
10) "0.01"
11) Expansion rate
12) (integer) 2
13) Tightening ratio
14) "0.5"
15) Max scaled capacity
16) (integer) 26214300
127.0.0.1:6379> BF.INFO key CAPACITY
(integer) 100

bf.insert

If the bloom filter does not exist under the specified name, a bloom filter is created with the specified parameters. Default properties will be used if the options below are not specified.

When the ITEMS option is provided, all items provided will be attempted to be added.

Insert Fields

Due to the nature of NONSCALING and VALIDATESCALETO arguments, specifying NONSCALING and VALIDATESCALETO together is not allowed.

Examples

127.0.0.1:6379> BF.INSERT key ITEMS item1 item2
1) (integer) 1
2) (integer) 1
# This does not update the capacity since the filter already exists. It only adds the provided items.
127.0.0.1:6379> BF.INSERT key CAPACITY 1000 ITEMS item2 item3
1) (integer) 0
2) (integer) 1
127.0.0.1:6379> BF.INSERT key_new CAPACITY 1000
[]
127.0.0.1:6379> BF.INSERT key NONSCALING VALIDATESCALETO 100
(error) ERR cannot use NONSCALING and VALIDATESCALETO options together
127.0.0.1:6379> BF.INSERT key CAPACITY 1000  VALIDATESCALETO 999999999999999999 ITEMS item2 item3
(error) ERR provided VALIDATESCALETO causes bloom object to exceed memory limit
127.0.0.1:6379> BF.INSERT key VALIDATESCALETO 999999999999999999 EXPANSION 1 ITEMS item2 item3
(error) ERR provided VALIDATESCALETO causes false positive to degrade to 0
127.0.0.1:6379> BF.INSERT key NOCREATE ITEMS item1 item2
(error) ERR not found

bf.load

Restores a bloom filter from a dump of an existing bloom filter with all of its specific the properties and bit vector dump of sub filter/s. This command is only generated during AOF rewrite to restore a bloom filter in the future.

bf.madd

Adds one or more items to a bloom filter. If the specified bloom filter does not exist, a bloom filter is created with the provided name with default properties.

If you want to create a bloom filter with non-default properties, use the BF.INSERT or BF.RESERVE command.

Examples

127.0.0.1:6379> BF.MADD key item1 item2
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> BF.MADD key item2 item3
1) (integer) 0
2) (integer) 1
127.0.0.1:6379> BF.MADD key_new item1
1) (integer) 1

bf.mexists

Determines if the provided item/s have been added to a bloom filter previously.

A Bloom filter has two possible responses when you check if an item exists:

Examples

127.0.0.1:6379> BF.MADD key item1 item2
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> BF.MEXISTS key item1 item2 item3
1) (integer) 1
2) (integer) 1
3) (integer) 0
127.0.0.1:6379> BF.MEXISTS key item1
1) (integer) 1

bf.reserve

Creates an empty bloom filter with the specified capacity and false positive rate. By default, a scaling filter is created with the default expansion rate.

To specify the scaling / non scaling nature of the bloom filter, use the options: NONSCALING or SCALING <expansion rate>. It is invalid to provide both options together.

Reserve fields

Examples

127.0.0.1:6379> BF.RESERVE key 0.01 1000
OK
127.0.0.1:6379> BF.RESERVE key 0.1 1000000
(error) ERR item exists
127.0.0.1:6379> BF.RESERVE bf_expansion 0.0001 5000 EXPANSION 3
OK
127.0.0.1:6379> BF.RESERVE bf_nonscaling 0.0001 5000 NONSCALING
OK

bgrewriteaof

Instruct Valkey to start an Append Only File rewrite process. The rewrite will create a small optimized version of the current Append Only File.

If BGREWRITEAOF fails, no data gets lost as the old AOF will be untouched.

The rewrite will be only triggered by Valkey if there is not already a background process doing persistence.

Specifically:

The AOF rewrite is automatically triggered by Valkey, however the BGREWRITEAOF command can be used to trigger a rewrite at any time.

Please refer to the persistence documentation for detailed information.

bgsave

Save the DB in background.

Normally the OK code is immediately returned. Valkey forks, the parent continues to serve the clients, the child saves the DB on disk then exits.

An error is returned if there is already a background save running or if there is another non-background-save process running, specifically an in-progress AOF rewrite.

If BGSAVE SCHEDULE is used, the command will immediately return OK when an AOF rewrite is in progress and schedule the background save to run at the next opportunity.

If BGSAVE CANCEL is used, it will immediately terminate any in-progress RDB save or replication full sync process. In case a background save is scheduled to run (e.g. using BGSAVE SCHEDULE command) the scheduled execution will be cancelled as well.

A client may be able to check if the operation succeeded using the LASTSAVE command.

Please refer to the persistence documentation for detailed information.

bitcount

Count the number of set bits (population counting) in a string.

By default all the bytes contained in the string are examined. It is possible to specify the counting operation only in an interval passing the additional arguments start and end.

Similar to the GETRANGE command, start and end can contain negative values in order to index bytes starting from the end of the string, where -1 is the last byte, -2 is the penultimate, and so forth.

Non-existent keys are treated as empty strings, so the command will return zero.

By default, the additional arguments start and end specify a byte index. We can use an additional argument BIT to specify a bit index. So 0 is the first bit, 1 is the second bit, and so forth. For negative values, -1 is the last bit, -2 is the penultimate, and so forth.

Examples

127.0.0.1:6379> SET mykey "foobar"
OK
127.0.0.1:6379> BITCOUNT mykey
(integer) 26
127.0.0.1:6379> BITCOUNT mykey 0 0
(integer) 4
127.0.0.1:6379> BITCOUNT mykey 1 1
(integer) 6
127.0.0.1:6379> BITCOUNT mykey 1 1 BYTE
(integer) 6
127.0.0.1:6379> BITCOUNT mykey 5 30 BIT
(integer) 17

Pattern: real-time metrics using bitmaps

Bitmaps are a very space-efficient representation of certain kinds of information. One example is a Web application that needs the history of user visits, so that for instance it is possible to determine what users are good targets of beta features.

Using the SETBIT command, this is trivial to accomplish, identifying every day with a small progressive integer. For instance day 0 is the first day the application was put online, day 1 the next day, and so forth.

Every time a user performs a page view, the application can register that in the current day the user visited the web site using the SETBIT command setting the bit corresponding to the current day.

Later it will be trivial to know the number of single days the user visited the web site simply calling the BITCOUNT command against the bitmap.

A similar pattern where user IDs are used instead of days is described in the article called "Fast easy realtime metrics using Redis bitmaps".

Performance considerations

In the above example of counting days, even after 10 years the application is online we still have just 365*10 bits of data per user, that is just 456 bytes per user. With this amount of data BITCOUNT is still as fast as any other O(1) Valkey command like GET or INCR.

When the bitmap is big, there are two alternatives:

bitfield

The command treats a string as an array of bits, and is capable of addressing specific integer fields of varying bit widths and arbitrary non (necessary) aligned offset. In practical terms using this command you can set, for example, a signed 5 bits integer at bit offset 1234 to a specific value, retrieve a 31 bit unsigned integer from offset 4567. Similarly the command handles increments and decrements of the specified integers, providing guaranteed and well specified overflow and underflow behavior that the user can configure.

BITFIELD is able to operate with multiple bit fields in the same command call. It takes a list of operations to perform, and returns an array of replies, where each array matches the corresponding operation in the list of arguments.

For example the following command increments a 5 bit signed integer at bit offset 100, and gets the value of the 4 bit unsigned integer at bit offset 0:

> BITFIELD mykey INCRBY i5 100 1 GET u4 0
1) (integer) 1
2) (integer) 0

Note that:

  1. Addressing with !GET bits outside the current string length (including the case the key does not exist at all), results in the operation to be performed like the missing part all consists of bits set to 0.
  2. Addressing with !SET or !INCRBY bits outside the current string length will enlarge the string, zero-padding it, as needed, for the minimal length needed, according to the most far bit touched.

Supported subcommands and integer encoding

The following is the list of supported commands.

There is another subcommand that only changes the behavior of successive !INCRBY and !SET subcommands calls by setting the overflow behavior:

Where an integer encoding is expected, it can be composed by prefixing with i for signed integers and u for unsigned integers with the number of bits of our integer encoding. So for example u8 is an unsigned integer of 8 bits and i16 is a signed integer of 16 bits.

The supported encodings are up to 64 bits for signed integers, and up to 63 bits for unsigned integers. This limitation with unsigned integers is due to the fact that currently the Valkey protocol is unable to return 64 bit unsigned integers as replies.

Bits and positional offsets

There are two ways in order to specify offsets in the bitfield command. If a number without any prefix is specified, it is used just as a zero based bit offset inside the string.

However if the offset is prefixed with a # character, the specified offset is multiplied by the integer encoding's width, so for example:

BITFIELD mystring SET i8 #0 100 SET i8 #1 200

Will set the first i8 integer at offset 0 and the second at offset 8. This way you don't have to do the math yourself inside your client if what you want is a plain array of integers of a given size.

Overflow control

Using the OVERFLOW command the user is able to fine-tune the behavior of the increment or decrement overflow (or underflow) by specifying one of the following behaviors:

Note that each OVERFLOW statement only affects the !INCRBY and !SET commands that follow it in the list of subcommands, up to the next OVERFLOW statement.

By default, WRAP is used if not otherwise specified.

> BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1
1) (integer) 1
2) (integer) 1
> BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1
1) (integer) 2
2) (integer) 2
> BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1
1) (integer) 3
2) (integer) 3
> BITFIELD mykey incrby u2 100 1 OVERFLOW SAT incrby u2 102 1
1) (integer) 0
2) (integer) 3

The following is an example of OVERFLOW FAIL returning NULL.

> BITFIELD mykey OVERFLOW FAIL incrby u2 102 1
1) (nil)

Motivations

The motivation for this command is that the ability to store many small integers as a single large bitmap (or segmented over a few keys to avoid having huge keys) is extremely memory efficient, and opens new use cases for Valkey to be applied, especially in the field of real time analytics. This use cases are supported by the ability to specify the overflow in a controlled way.

Fun fact: Reddit's 2017 April fools' project r/place was built using the BITFIELD command in order to take an in-memory representation of the collaborative canvas.

Performance considerations

Usually BITFIELD is a fast command, however note that addressing far bits of currently short strings will trigger an allocation that may be more costly than executing the command on bits already existing.

Orders of bits

The representation used by BITFIELD considers the bitmap as having the bit number 0 to be the most significant bit of the first byte, and so forth, so for example setting a 5 bits unsigned integer to value 23 at offset 7 into a bitmap previously set to all zeroes, will produce the following representation:

+--------+--------+
|00000001|01110000|
+--------+--------+

When offsets and integer sizes are aligned to bytes boundaries, this is the same as big endian, however when such alignment does not exist, its important to also understand how the bits inside a byte are ordered.

bitfield_ro

Read-only variant of the BITFIELD command. It is similar to the original BITFIELD but only accepts GET subcommand and can safely be used in read-only replicas.

Since the original BITFIELD has SET and INCRBY options, it is technically flagged as a writing command in the Valkey command table. For this reason, read-only replicas in a Valkey Cluster will redirect it to the master instance even if the connection is in read-only mode (see the READONLY command of Valkey Cluster).

See original BITFIELD for more details.

BITFIELD_RO hello GET i8 16

bitop

Perform a bitwise operation between multiple keys (containing string values) and store the result in the destination key.

The BITOP command supports four bitwise operations: AND, OR, XOR and NOT, thus the valid forms to call the command are:

As you can see NOT is special as it only takes an input key, because it performs inversion of bits so it only makes sense as a unary operator.

The result of the operation is always stored at destkey.

Handling of strings with different lengths

When an operation is performed between strings having different lengths, all the strings shorter than the longest string in the set are treated as if they were zero-padded up to the length of the longest string.

The same holds true for non-existent keys, that are considered as a stream of zero bytes up to the length of the longest string.

Examples

127.0.0.1:6379> SET key1 "foobar"
OK
127.0.0.1:6379> SET key2 "abcdef"
OK
127.0.0.1:6379> BITOP AND dest key1 key2
(integer) 6
127.0.0.1:6379> GET dest
"`bc`ab"

Pattern: real time metrics using bitmaps

BITOP is a good complement to the pattern documented in the BITCOUNT command documentation. Different bitmaps can be combined in order to obtain a target bitmap where the population counting operation is performed.

See the article called "Fast easy realtime metrics using Valkey bitmaps" for an interesting use cases.

Performance considerations

BITOP is a potentially slow command as it runs in O(N) time. Care should be taken when running it against long input strings.

For real-time metrics and statistics involving large inputs a good approach is to use a replica (with replica-read-only option enabled) where the bit-wise operations are performed to avoid blocking the primary instance.

bitpos

Return the position of the first bit set to 1 or 0 in a string.

The position is returned, thinking of the string as an array of bits from left to right, where the first byte's most significant bit is at position 0, the second byte's most significant bit is at position 8, and so forth.

The same bit position convention is followed by GETBIT and SETBIT.

By default, all the bytes contained in the string are examined. It is possible to look for bits only in a specified interval by passing the additional arguments start and end. You can also just pass start, the operation will assume that the end is the last byte of the string. However there are semantic differences as explained later. By default, the range is interpreted as a range of bytes and not a range of bits, so start=0 and end=2 means to look at the first three bytes.

You can use the optional BIT modifier to specify that the range should be interpreted as a range of bits. So start=0 and end=2 means to look at the first three bits.

Note that bit positions are returned always as absolute values starting from bit zero even when start and end are used to specify a range.

Similar to the GETRANGE command, start and end can contain negative values in order to index bytes starting from the end of the string, where -1 is the last byte, -2 is the penultimate, and so forth. When BIT is specified, -1 is the last bit, -2 is the penultimate, and so forth.

Non-existent keys are treated as empty strings.

Examples

127.0.0.1:6379> SET mykey "\xff\xf0\x00"
OK
127.0.0.1:6379> BITPOS mykey 0
(integer) 12
127.0.0.1:6379> SET mykey "\x00\xff\xf0"
OK
127.0.0.1:6379> BITPOS mykey 1 0
(integer) 8
127.0.0.1:6379> BITPOS mykey 1 2
(integer) 16
127.0.0.1:6379> BITPOS mykey 1 2 -1 BYTE
(integer) 16
127.0.0.1:6379> BITPOS mykey 1 7 15 BIT
(integer) 8
127.0.0.1:6379> set mykey "\x00\x00\x00"
OK
127.0.0.1:6379> BITPOS mykey 1
(integer) -1
127.0.0.1:6379> BITPOS mykey 1 7 -3 BIT
(integer) -1

blmove

BLMOVE is the blocking variant of LMOVE. When source contains elements, this command behaves exactly like LMOVE. When used inside a MULTI/EXEC block, this command behaves exactly like LMOVE. When source is empty, Valkey will block the connection until another client pushes to it or until timeout (a double value specifying the maximum number of seconds to block) is reached. A timeout of zero can be used to block indefinitely.

This command comes in place of the now deprecated BRPOPLPUSH. Doing BLMOVE RIGHT LEFT is equivalent.

See LMOVE for more information.

Pattern: Reliable queue

Please see the pattern description in the LMOVE documentation.

Pattern: Circular list

Please see the pattern description in the LMOVE documentation.

blmpop

BLMPOP is the blocking variant of LMPOP.

When any of the lists contains elements, this command behaves exactly like LMPOP. When used inside a MULTI/EXEC block, this command behaves exactly like LMPOP. When all lists are empty, Valkey will block the connection until another client pushes to it or until the timeout (a double value specifying the maximum number of seconds to block) elapses. A timeout of zero can be used to block indefinitely.

See LMPOP for more information.

blpop

BLPOP is a blocking list pop primitive. It is the blocking version of LPOP because it blocks the connection when there are no elements to pop from any of the given lists. An element is popped from the head of the first list that is non-empty, with the given keys being checked in the order that they are given.

Non-blocking behavior

When BLPOP is called, if at least one of the specified keys contains a non-empty list, an element is popped from the head of the list and returned to the caller together with the key it was popped from.

Keys are checked in the order that they are given. Let's say that the key list1 doesn't exist and list2 and list3 hold non-empty lists. Consider the following command:

BLPOP list1 list2 list3 0

BLPOP guarantees to return an element from the list stored at list2 (since it is the first non empty list when checking list1, list2 and list3 in that order).

Blocking behavior

If none of the specified keys exist, BLPOP blocks the connection until another client performs an LPUSH or RPUSH operation against one of the keys.

Once new data is present on one of the lists, the client returns with the name of the key unblocking it and the popped value.

When BLPOP causes a client to block and a non-zero timeout is specified, the client will unblock returning a nil multi-bulk value when the specified timeout has expired without a push operation against at least one of the specified keys.

The timeout argument is interpreted as a double value specifying the maximum number of seconds to block. A timeout of zero can be used to block indefinitely.

What key is served first? What client? What element? Priority ordering details.

Behavior of BLPOP when multiple elements are pushed inside a list.

There are times when a list can receive multiple elements in the context of the same conceptual command:

What happens is that the command performing multiple pushes is executed, and only after the execution of the command the blocked clients are served. Consider this sequence of commands.

Client A:   BLPOP foo 0
Client B:   LPUSH foo a b c

If the above condition happens using a Redis OSS 2.6 server or greater, Client A will be served with the c element, because after the LPUSH command the list contains c,b,a, so taking an element from the left means to return c.

Note that for the same reason a Lua script or a MULTI/EXEC block may push elements into a list and afterward delete the list. In this case the blocked clients will not be served at all and will continue to be blocked as long as no data is present on the list after the execution of a single command, transaction, or script.

BLPOP inside a MULTI / EXEC transaction

BLPOP can be used with pipelining (sending multiple commands and reading the replies in batch), however this setup makes sense almost solely when it is the last command of the pipeline.

Using BLPOP inside a MULTI/EXEC block does not make a lot of sense as it would require blocking the entire server in order to execute the block atomically, which in turn does not allow other clients to perform a push operation. For this reason the behavior of BLPOP inside MULTI / EXEC when the list is empty is to return a nil multi-bulk reply, which is the same thing that happens when the timeout is reached.

If you like science fiction, think of time flowing at infinite speed inside a MULTI / EXEC block...

Examples

127.0.0.1:6379> DEL list1 list2
(integer) 0
127.0.0.1:6379> RPUSH list1 a b c
(integer) 3
127.0.0.1:6379> BLPOP list1 list2 0
1) "list1"
2) "a"

Reliable queues

When BLPOP returns an element to the client, it also removes the element from the list. This means that the element only exists in the context of the client: if the client crashes while processing the returned element, it is lost forever.

This can be a problem with some application where we want a more reliable messaging system. When this is the case, please check the BRPOPLPUSH command, that is a variant of BLPOP that adds the returned element to a target list before returning it to the client.

Pattern: Event notification

Using blocking list operations it is possible to mount different blocking primitives. For instance for some application you may need to block waiting for elements into a Set, so that as far as a new element is added to the Set, it is possible to retrieve it without resort to polling. This would require a blocking version of SPOP that is not available, but using blocking list operations we can easily accomplish this task.

The consumer will do:

LOOP forever
    WHILE SPOP(key) returns elements
        ... process elements ...
    END
    BRPOP helper_key
END

While in the producer side we'll use simply:

MULTI
SADD key element
LPUSH helper_key x
EXEC

brpop

BRPOP is a blocking list pop primitive. It is the blocking version of RPOP because it blocks the connection when there are no elements to pop from any of the given lists. An element is popped from the tail of the first list that is non-empty, with the given keys being checked in the order that they are given.

See the BLPOP documentation for the exact semantics, since BRPOP is identical to BLPOP with the only difference being that it pops elements from the tail of a list instead of popping from the head.

Examples

127.0.0.1:6379> DEL list1 list2
(integer) 0
127.0.0.1:6379> RPUSH list1 a b c
(integer) 3
127.0.0.1:6379> BRPOP list1 list2 0
1) "list1"
2) "c"

brpoplpush

BRPOPLPUSH is the blocking variant of RPOPLPUSH. When source contains elements, this command behaves exactly like RPOPLPUSH. When used inside a MULTI/EXEC block, this command behaves exactly like RPOPLPUSH. When source is empty, Valkey will block the connection until another client pushes to it or until timeout is reached. A timeout of zero can be used to block indefinitely.

See RPOPLPUSH for more information.

Pattern: Reliable queue

Please see the pattern description in the RPOPLPUSH documentation.

Pattern: Circular list

Please see the pattern description in the RPOPLPUSH documentation.

Alternative

BLMOVE with the RIGHT and LEFT arguments.

bzmpop

BZMPOP is the blocking variant of ZMPOP.

When any of the sorted sets contains elements, this command behaves exactly like ZMPOP. When used inside a MULTI/EXEC block, this command behaves exactly like ZMPOP. When all sorted sets are empty, Valkey will block the connection until another client adds members to one of the keys or until the timeout (a double value specifying the maximum number of seconds to block) elapses. A timeout of zero can be used to block indefinitely.

See ZMPOP for more information.

bzpopmax

BZPOPMAX is the blocking variant of the sorted set ZPOPMAX primitive.

It is the blocking version because it blocks the connection when there are no members to pop from any of the given sorted sets. A member with the highest score is popped from first sorted set that is non-empty, with the given keys being checked in the order that they are given.

The timeout argument is interpreted as a double value specifying the maximum number of seconds to block. A timeout of zero can be used to block indefinitely.

See the BZPOPMIN documentation for the exact semantics, since BZPOPMAX is identical to BZPOPMIN with the only difference being that it pops members with the highest scores instead of popping the ones with the lowest scores.

Examples

127.0.0.1:6379> DEL zset1 zset2
(integer) 0
127.0.0.1:6379> ZADD zset1 0 a 1 b 2 c
(integer) 3
127.0.0.1:6379> BZPOPMAX zset1 zset2 0
1) "zset1"
2) "c"
3) "2"

bzpopmin

BZPOPMIN is the blocking variant of the sorted set ZPOPMIN primitive.

It is the blocking version because it blocks the connection when there are no members to pop from any of the given sorted sets. A member with the lowest score is popped from first sorted set that is non-empty, with the given keys being checked in the order that they are given.

The timeout argument is interpreted as a double value specifying the maximum number of seconds to block. A timeout of zero can be used to block indefinitely.

See the BLPOP documentation for the exact semantics, since BZPOPMIN is identical to BLPOP with the only difference being the data structure being popped from.

Examples

127.0.0.1:6379> DEL zset1 zset2
(integer) 0
127.0.0.1:6379> ZADD zset1 0 a 1 b 2 c
(integer) 3
127.0.0.1:6379> BZPOPMIN zset1 zset2 0
1) "zset1"
2) "a"
3) "0"

client-caching

This command controls the tracking of the keys in the next command executed by the connection, when tracking is enabled in OPTIN or OPTOUT mode. Please check the client side caching documentation for background information.

When tracking is enabled Valkey, using the CLIENT TRACKING command, it is possible to specify the OPTIN or OPTOUT options, so that keys in read only commands are not automatically remembered by the server to be invalidated later. When we are in OPTIN mode, we can enable the tracking of the keys in the next command by calling CLIENT CACHING yes immediately before it. Similarly when we are in OPTOUT mode, and keys are normally tracked, we can avoid the keys in the next command to be tracked using CLIENT CACHING no.

Basically the command sets a state in the connection, that is valid only for the next command execution, that will modify the behavior of client tracking.

client-capa

Clients can declare their capabilities to Valkey using the CLIENT CAPA command, and Valkey will adjust the corresponding features for the current connection based on the declared client capabilities.

Multiple capabilities can be declared in the command. If any capabilities are unrecognized, Valkey will ignore them instead of returning an error.

The capabilities currently supported are:

client-getname

The CLIENT GETNAME returns the name of the current connection as set by CLIENT SETNAME. Since every new connection starts without an associated name, if no name was assigned a null bulk reply is returned.

client-getredir

This command returns the client ID we are redirecting our tracking notifications to. We set a client to redirect to when using CLIENT TRACKING to enable tracking. However in order to avoid forcing client libraries implementations to remember the ID notifications are redirected to, this command exists in order to improve introspection and allow clients to check later if redirection is active and towards which client ID.

client-help

The CLIENT HELP command returns a helpful text describing the different subcommands.

client-id

The command just returns the ID of the current connection. Every connection ID has certain guarantees:

  1. It is never repeated, so if CLIENT ID returns the same number, the caller can be sure that the underlying client did not disconnect and reconnect the connection, but it is still the same connection.
  2. The ID is monotonically incremental. If the ID of a connection is greater than the ID of another connection, it is guaranteed that the second connection was established with the server at a later time.

This command is especially useful together with CLIENT UNBLOCK. Check the CLIENT UNBLOCK command page for a pattern involving the two commands.

Examples

127.0.0.1:6379> CLIENT ID
(integer) 2873

client-import-source

When the client sync data from a Redis-like server to Valkey using some sync tools like RedisShake, Valkey performs expiration and eviction as usual because it's a primary, which may cause data corruption. For example, the client calls set key 1 ex 1 on the source server and this command is transferred to the destination server. Then the client calls incr key on the source server before the key expired, there will be a key on the source server with the value of 2. But when the command arrived at the destination server, the key may be expired and has deleted. So there will be a key on the destination server with the value of 1, which is inconsistent with the source server. Sync tools can solve this problem by setting import-mode config to yes and declaring their connections as IMPORT-SOURCE.

The CLIENT IMPORT-SOURCE command mark this client as an import source if import-mode is enabled and can visit expired keys. The following modes are available:

Notes

The server needs to be configured with import-mode yes before marking a client connection as an import source.

client-info

The command returns information and statistics about the current client connection in a mostly human readable format.

The reply format is identical to that of CLIENT LIST, and the content consists only of information about the current client.

Examples

127.0.0.1:6379> CLIENT INFO
id=2875 addr=127.0.0.1:38610 laddr=127.0.0.1:6379 fd=10 name= age=0 idle=0 flags=N capa= db=0 sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=26 qbuf-free=20448 argv-mem=10 multi-mem=0 rbs=16384 rbp=16384 obl=0 oll=0 omem=0 tot-mem=37786 events=r cmd=client|info user=default redir=-1 resp=2 lib-name= lib-ver=

client-kill

The CLIENT KILL command closes a given client connection. This command support two formats, the old format:

CLIENT KILL addr:port

The ip:port should match a line returned by the CLIENT LIST command (addr field).

The new format:

CLIENT KILL <filter> <value> ... ... <filter> <value>

With the new form it is possible to kill clients by different attributes instead of killing just by address. The following filters are available:

It is possible to provide multiple filters at the same time. The command will handle multiple filters via logical AND. For example:

CLIENT KILL addr 127.0.0.1:12345 type pubsub

is valid and will kill only a pubsub client with the specified address. This format containing multiple filters is rarely useful currently.

When the new form is used the command no longer returns OK or an error, but instead the number of killed clients, that may be zero.

CLIENT KILL and Valkey Sentinel

Valkey Sentinel uses CLIENT KILL to terminate client connections when an instance is reconfigured. This mechanism ensures that clients re-establish a connection with a Sentinel, refreshing their configurations.

Notes

Due to the single-threaded nature of Valkey, it is not possible to kill a client connection while it is executing a command. From the client point of view, the connection can never be closed in the middle of the execution of a command. However, the client will notice the connection has been closed only when the next command is sent (and results in network error).

client-list

The CLIENT LIST command returns information and statistics about the client connections server in a mostly human readable format.

You can use one or more optional arguments to filter the list:

Filters can be combined to perform more precise searches. The command will handle multiple filters via logical AND.

Here is the meaning of the fields:

The client flags can be a combination of:

A: connection to be closed ASAP
b: the client is waiting in a blocking operation
c: connection to be closed after writing entire reply
d: a watched keys has been modified - EXEC will fail
e: the client is excluded from the client eviction mechanism
i: the client is waiting for a VM I/O (deprecated)
M: the client is a primary
N: no specific flag set
O: the client is a client in MONITOR mode
P: the client is a Pub/Sub subscriber
r: the client is in readonly mode against a cluster node
S: the client is a replica node connection to this instance
u: the client is unblocked
U: the client is connected via a Unix domain socket
x: the client is in a MULTI/EXEC context
t: the client enabled keys tracking in order to perform client side caching
T: the client will not touch the LRU/LFU of the keys it accesses
R: the client tracking target client is invalid
B: the client enabled broadcast tracking mode
I: the client is an import source

Client's capabilities can be:

r: the client can handle redirect messages

The file descriptor events can be:

r: the client socket is readable (event loop)
w: the client socket is writable (event loop)

Examples

CLIENT LIST TYPE normal USER admin MAXAGE 5000 ID 1234 5678
id=1234 addr=127.0.0.1:64000 laddr=127.0.0.1:6379 fd=5 name= age=600 idle=300 flags= db=0 sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 tot-mem=1024 events=r cmd=client|list user=default redir=-1 resp=2 lib-name= lib-ver=
id=5678 addr=127.0.0.1:64001 laddr=127.0.0.1:6379 fd=6 name= age=900 idle=450 flags= db=0 sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 tot-mem=2048 events=r cmd=client|list user=default redir=-1 resp=2 lib-name= lib-ver=

Notes

New fields are regularly added for debugging purpose. Some could be removed in the future. A version safe Valkey client using this command should parse the output accordingly (i.e. handling gracefully missing fields, skipping unknown fields).

client-no-evict

The CLIENT NO-EVICT command sets the client eviction mode for the current connection.

When turned on and client eviction is configured, the current connection will be excluded from the client eviction process even if we're above the configured client eviction threshold.

When turned off, the current client will be re-included in the pool of potential clients to be evicted (and evicted if needed).

See client eviction for more details.

client-no-touch

The CLIENT NO-TOUCH command controls whether commands sent by the client will alter the LRU/LFU of the keys they access.

When turned on, the current client will not change LFU/LRU stats, unless it sends the TOUCH command.

When turned off, the client touches LFU/LRU stats just as a normal client.

client-pause

CLIENT PAUSE is a connections control command able to suspend all the Valkey clients for the specified amount of time (in milliseconds).

The command performs the following actions:

Client pause currently supports two modes:

For the WRITE mode, some commands have special behavior:

This command is useful as it makes able to switch clients from a Valkey instance to another one in a controlled way. For example during an instance upgrade the system administrator could do the following:

This command also prevents keys to be evicted or expired during the time clients are paused. This way the dataset is guaranteed to be static not just from the point of view of clients not being able to write, but also from the point of view of internal operations.

client-reply

Sometimes it can be useful for clients to completely disable replies from the Valkey server. For example when the client sends fire and forget commands or performs a mass loading of data, or in caching contexts where new data is streamed constantly. In such contexts to use server time and bandwidth in order to send back replies to clients, which are going to be ignored, is considered wasteful.

The CLIENT REPLY command controls whether the server will reply the client's commands. The following modes are available:

Note: Starting with Valkey 9.0, the CLIENT REPLY command is disallowed inside a transaction (MULTI/EXEC). In earlier versions, using CLIENT REPLY within a transaction could corrupt the reply stream. Attempting to use it within a transaction now results in an error reply.

client-setinfo

The CLIENT SETINFO command assigns various info attributes to the current connection which are displayed in the output of CLIENT LIST and CLIENT INFO.

Client libraries are expected to pipeline this command after authentication on all connections and ignore failures since they could be connected to an older version that doesn't support them.

Currently the supported attributes are:

There is no limit to the length of these attributes. However it is not possible to use spaces, newlines, or other non-printable characters that would violate the format of the CLIENT LIST reply.

Note that these attributes are not cleared by the RESET command.

client-setname

The CLIENT SETNAME command assigns a name to the current connection.

The assigned name is displayed in the output of CLIENT LIST so that it is possible to identify the client that performed a given connection.

For instance when Valkey is used in order to implement a queue, producers and consumers of messages may want to set the name of the connection according to their role.

There is no limit to the length of the name that can be assigned if not the usual limits of the String type (512 MB). However it is not possible to use spaces in the connection name as this would violate the format of the CLIENT LIST reply.

It is possible to entirely remove the connection name setting it to the empty string, that is not a valid connection name since it serves to this specific purpose.

The connection name can be inspected using CLIENT GETNAME.

Every new connection starts without an assigned name.

Tip: setting names to connections is a good way to debug connection leaks due to bugs in the application using Valkey.

client-tracking

This command enables the tracking feature of the Valkey server, that is used for server assisted client side caching.

When tracking is enabled Valkey remembers the keys that the connection requested, in order to send later invalidation messages when such keys are modified. Invalidation messages are sent in the same connection (only available when the RESP3 protocol is used) or redirected in a different connection (available also with RESP2 and Pub/Sub). A special broadcasting mode is available where clients participating in this protocol receive every notification just subscribing to given key prefixes, regardless of the keys that they requested. Given the complexity of the argument please refer to the main client side caching documentation for the details. This manual page is only a reference for the options of this subcommand.

In order to enable tracking, use:

CLIENT TRACKING on ... options ...

The feature will remain active in the current connection for all its life, unless tracking is turned off with CLIENT TRACKING off at some point.

The following are the list of options that modify the behavior of the command when enabling tracking:

client-trackinginfo

The command returns information about the current client connection's use of the server assisted client side caching feature.

Here's the list of tracking information sections and their respective values:

client-unblock

This command can unblock, from a different connection, a client blocked in a blocking operation, such as for instance BRPOP or XREAD or WAIT.

By default the client is unblocked as if the timeout of the command was reached, however if an additional (and optional) argument is passed, it is possible to specify the unblocking behavior, that can be TIMEOUT (the default) or ERROR. If ERROR is specified, the behavior is to unblock the client returning as error the fact that the client was force-unblocked. Specifically the client will receive the following error:

-UNBLOCKED client unblocked via CLIENT UNBLOCK

Note: of course as usually it is not guaranteed that the error text remains the same, however the error code will remain -UNBLOCKED.

This command is useful especially when we are monitoring many keys with a limited number of connections. For instance we may want to monitor multiple streams with XREAD without using more than N connections. However at some point the consumer process is informed that there is one more stream key to monitor. In order to avoid using more connections, the best behavior would be to stop the blocking command from one of the connections in the pool, add the new key, and issue the blocking command again.

To obtain this behavior the following pattern is used. The process uses an additional control connection in order to send the CLIENT UNBLOCK command if needed. In the meantime, before running the blocking operation on the other connections, the process runs CLIENT ID in order to get the ID associated with that connection. When a new key should be added, or when a key should no longer be monitored, the relevant connection blocking command is aborted by sending CLIENT UNBLOCK in the control connection. The blocking command will return and can be finally reissued.

This example shows the application in the context of streams, however the pattern is a general one and can be applied to other cases.

Examples

Connection A (blocking connection):
> CLIENT ID
2934
> BRPOP key1 key2 key3 0
(client is blocked)

... Now we want to add a new key ...

Connection B (control connection):
> CLIENT UNBLOCK 2934
1

Connection A (blocking connection):
... BRPOP reply with timeout ...
NULL
> BRPOP key1 key2 key3 key4 0
(client is blocked again)

client-unpause

CLIENT UNPAUSE is used to resume command processing for all clients that were paused by CLIENT PAUSE.

client

This is a container command for client connection commands.

To see the list of available commands you can call CLIENT HELP.

cluster-addslots

This command is useful in order to modify a node's view of the cluster configuration. Specifically it assigns a set of hash slots to the node receiving the command. If the command is successful, the node will map the specified hash slots to itself, and will start broadcasting the new configuration.

However note that:

  1. The command only works if all the specified slots are, from the point of view of the node receiving the command, currently not assigned. A node will refuse to take ownership for slots that already belong to some other node (including itself).
  2. The command fails if the same slot is specified multiple times.
  3. As a side effect of the command execution, if a slot among the ones specified as argument is set as importing, this state gets cleared once the node assigns the (previously unbound) slot to itself.

Example

For example the following command assigns slots 1 2 3 to the node receiving the command:

> CLUSTER ADDSLOTS 1 2 3
OK

However trying to execute it again results into an error since the slots are already assigned:

> CLUSTER ADDSLOTS 1 2 3
ERR Slot 1 is already busy

Usage in Valkey Cluster

This command only works in cluster mode and is useful in the following Valkey Cluster operations:

  1. To create a new cluster ADDSLOTS is used in order to initially setup primary nodes splitting the available hash slots among them.
  2. In order to fix a broken cluster where certain slots are unassigned.

Information about slots propagation and warnings

Note that once a node assigns a set of slots to itself, it will start propagating this information in heartbeat packet headers. However the other nodes will accept the information only if they have the slot as not already bound with another node, or if the configuration epoch of the node advertising the new hash slot, is greater than the node currently listed in the table.

This means that this command should be used with care only by applications orchestrating Valkey Cluster, like valkey-cli, and the command if used out of the right context can leave the cluster in a wrong state or cause data loss.

cluster-addslotsrange

The CLUSTER ADDSLOTSRANGE is similar to the CLUSTER ADDSLOTS command in that they both assign hash slots to nodes.

The difference between the two commands is that CLUSTER ADDSLOTS takes a list of slots to assign to the node, while CLUSTER ADDSLOTSRANGE takes a list of slot ranges (specified by start and end slots) to assign to the node.

Example

To assign slots 1 2 3 4 5 to the node, the CLUSTER ADDSLOTS command is:

> CLUSTER ADDSLOTS 1 2 3 4 5
OK

The same operation can be completed with the following CLUSTER ADDSLOTSRANGE command:

> CLUSTER ADDSLOTSRANGE 1 5
OK

Usage in Valkey Cluster

This command only works in cluster mode and is useful in the following Valkey Cluster operations:

  1. To create a new cluster, CLUSTER ADDSLOTSRANGE is used to initially set up primary nodes splitting the available hash slots among them.
  2. In order to fix a broken cluster where certain slots are unassigned.

cluster-bumpepoch

Advances the cluster config epoch.

The CLUSTER BUMPEPOCH command triggers an increment to the cluster's config epoch from the connected node. The epoch will be incremented if the node's config epoch is zero, or if it is less than the cluster's greatest epoch.

Note: config epoch management is performed internally by the cluster, and relies on obtaining a consensus of nodes. The CLUSTER BUMPEPOCH attempts to increment the config epoch WITHOUT getting the consensus, so using it may violate the "last failover wins" rule. Use it with caution.

cluster-cancelslotmigrations

CLUSTER CANCELSLOTMIGRATIONS cancels all in progress atomic slot migrations initiated through CLUSTER MIGRATESLOTS.

Only slot migrations initiated on this node are cancelled. If this node is the target of a slot migration, the cancellation must be performed on the source node.

Because the migrations being cancelled may touch keys in any database, the caller must have ACL access to all databases (the alldbs rule). See database permissions.

cluster-count-failure-reports

The command returns the number of failure reports for the specified node. Failure reports are the way Valkey Cluster uses in order to promote a PFAIL state, that means a node is not reachable, to a FAIL state, that means that the majority of primaries in the cluster agreed within a window of time that the node is not reachable.

A few more details:

This command returns the number of failure reports for the current node which are currently not expired (so received within two times the node timeout time). The count does not include what the node we are asking this count believes about the node ID we pass as argument, the count only includes the failure reports the node received from other nodes.

This command is mainly useful for debugging, when the failure detector of Valkey Cluster is not operating as we believe it should.

cluster-countkeysinslot

Returns the number of keys in the specified Valkey Cluster hash slot in the currently selected database. The command only queries the local data set, so contacting a node that is not serving the specified hash slot will always result in a count of zero being returned.

> CLUSTER COUNTKEYSINSLOT 7000
(integer) 50341

cluster-delslots

In Valkey Cluster, each node keeps track of which primary is serving a particular hash slot.

The CLUSTER DELSLOTS command asks a particular Valkey Cluster node to forget which primary is serving the hash slots specified as arguments.

In the context of a node that has received a CLUSTER DELSLOTS command and has consequently removed the associations for the passed hash slots, we say those hash slots are unbound. Note that the existence of unbound hash slots occurs naturally when a node has not been configured to handle them (something that can be done with the CLUSTER ADDSLOTS command) and if it has not received any information about who owns those hash slots (something that it can learn from heartbeat or update messages).

If a node with unbound hash slots receives a heartbeat packet from another node that claims to be the owner of some of those hash slots, the association is established instantly. Moreover, if a heartbeat or update message is received with a configuration epoch greater than the node's own, the association is re-established.

However, note that:

  1. The command only works if all the specified slots are already associated with some node.
  2. The command fails if the same slot is specified multiple times.
  3. As a side effect of the command execution, the node may go into down state because not all hash slots are covered.

Example

The following command removes the association for slots 5000 and 5001 from the node receiving the command:

> CLUSTER DELSLOTS 5000 5001
OK

Usage in Valkey Cluster

This command only works in cluster mode and may be useful for debugging and in order to manually orchestrate a cluster configuration when a new cluster is created. It is currently not used by valkey-cli, and mainly exists for API completeness.

cluster-delslotsrange

The CLUSTER DELSLOTSRANGE command is similar to the CLUSTER DELSLOTS command in that they both remove hash slots from the node. The difference is that CLUSTER DELSLOTS takes a list of hash slots to remove from the node, while CLUSTER DELSLOTSRANGE takes a list of slot ranges (specified by start and end slots) to remove from the node.

Example

To remove slots 1 2 3 4 5 from the node, the CLUSTER DELSLOTS command is:

> CLUSTER DELSLOTS 1 2 3 4 5
OK

The same operation can be completed with the following CLUSTER DELSLOTSRANGE command:

> CLUSTER DELSLOTSRANGE 1 5
OK

However, note that:

  1. The command only works if all the specified slots are already associated with the node.
  2. The command fails if the same slot is specified multiple times.
  3. As a side effect of the command execution, the node may go into down state because not all hash slots are covered.

Usage in Valkey Cluster

This command only works in cluster mode and may be useful for debugging and in order to manually orchestrate a cluster configuration when a new cluster is created. It is currently not used by valkey-cli, and mainly exists for API completeness.

cluster-failover

This command, that can only be sent to a Valkey Cluster replica node, forces the replica to start a manual failover of its primary instance.

A manual failover is a special kind of failover that is usually executed when there are no actual failures, but we wish to swap the current primary with one of its replicas (which is the node we send the command to), in a safe way, without any window for data loss. It works in the following way:

  1. The replica tells the primary to stop processing queries from clients.
  2. The primary replies to the replica with the current replication offset.
  3. The replica waits for the replication offset to match on its side, to make sure it processed all the data from the primary before it continues.
  4. The replica starts a failover, obtains a new configuration epoch from the majority of the primaries, and broadcasts the new configuration.
  5. The old primary receives the configuration update: unblocks its clients and starts replying with redirection messages so that they'll continue the chat with the new primary.

This way clients are moved away from the old primary to the new primary atomically and only when the replica that is turning into the new primary has processed all of the replication stream from the old primary.

There is a built-in timeout for the primary to resume processing queries if the replica does not catch quickly enough or is unable to secure the votes to take over. The default failover timeout is 5000ms. It is possible to configure the timeout via the cluster-manual-failover-timeout configuration parameter (added in Valkey 8.1) and decide how long the primary will pause in the worst case scenario.

FORCE option: manual failover when the primary is down

The command behavior can be modified by two options: FORCE and TAKEOVER.

If the FORCE option is given, the replica does not perform any handshake with the primary, that may be not reachable, but instead just starts a failover ASAP starting from point 4. This is useful when we want to start a manual failover while the primary is no longer reachable.

However using FORCE we still need the majority of primaries to be available in order to authorize the failover and generate a new configuration epoch for the replica that is going to become primary.

TAKEOVER option: manual failover without cluster consensus

There are situations where this is not enough, and we want a replica to failover without any agreement with the rest of the cluster. A real world use case for this is to mass promote replicas in a different data center to primaries in order to perform a data center switch, while all the primaries are down or partitioned away.

The TAKEOVER option implies everything FORCE implies, but also does not uses any cluster authorization in order to failover. A replica receiving CLUSTER FAILOVER TAKEOVER will instead:

  1. Generate a new configEpoch unilaterally, just taking the current greatest epoch available and incrementing it if its local configuration epoch is not already the greatest.
  2. Assign itself all the hash slots of its primary, and propagate the new configuration to every node which is reachable ASAP, and eventually to every other node.

Note that TAKEOVER violates the last-failover-wins principle of Valkey Cluster, since the configuration epoch generated by the replica violates the normal generation of configuration epochs in several ways:

  1. There is no guarantee that it is actually the higher configuration epoch, since, for example, we can use the TAKEOVER option within a minority, nor any message exchange is performed to generate the new configuration epoch.
  2. If we generate a configuration epoch which happens to collide with another instance, eventually our configuration epoch, or the one of another instance with our same epoch, will be moved away using the configuration epoch collision resolution algorithm.

Because of this the TAKEOVER option should be used with care.

Implementation details and notes

cluster-flushslots

Deletes all slots from a node.

The CLUSTER FLUSHSLOTS deletes all information about slots from the connected node. It can only be called when the database is empty.

cluster-forget

The command is used in order to remove a node, specified via its node ID, from the set of known nodes of the Valkey Cluster node receiving the command. In other words the specified node is removed from the nodes table of the node receiving the command.

Because when a given node is part of the cluster, all the other nodes participating in the cluster knows about it, in order for a node to be completely removed from a cluster, the CLUSTER FORGET command must be sent to all the remaining nodes, regardless of the fact they are primaries or replicas.

However the command cannot simply drop the node from the internal node table of the node receiving the command, it also implements a ban-list, not allowing the same node to be added again as a side effect of processing the gossip section of the heartbeat packets received from other nodes.

Details on why the ban-list is needed

In the following example we'll show why the command must not just remove a given node from the nodes table, but also prevent it for being re-inserted again for some time.

Let's assume we have four nodes, A, B, C and D. In order to end with just a three nodes cluster A, B, C we may follow these steps:

  1. Reshard all the hash slots from D to nodes A, B, C.
  2. D is now empty, but still listed in the nodes table of A, B and C.
  3. We contact A, and send CLUSTER FORGET D.
  4. B sends node A a heartbeat packet, where node D is listed.
  5. A does no longer known node D (see step 3), so it starts a handshake with D.
  6. D ends re-added in the nodes table of A.

As you can see in this way removing a node is fragile, we need to send CLUSTER FORGET commands to all the nodes ASAP hoping there are no gossip sections processing in the meantime. Because of this problem the command implements a ban-list with an expire time for each entry.

So what the command really does is:

  1. The specified node gets removed from the nodes table.
  2. The node ID of the removed node gets added to the ban-list, for 1 minute.
  3. The node will skip all the node IDs listed in the ban-list when processing gossip sections received in heartbeat packets from other nodes.

This way we have a 60 second window to inform all the nodes in the cluster that we want to remove a node.

Special conditions not allowing the command execution

The command does not succeed and returns an error in the following cases:

  1. The specified node ID is not found in the nodes table.
  2. The node receiving the command is a replica, and the specified node ID identifies its current primary.
  3. The node ID identifies the same node we are sending the command to.

cluster-getkeysinslot

The command returns an array of key names stored in the contacted node and hashing to the specified hash slot in the currently selected database. The maximum number of keys to return is specified via the count argument, so that it is possible for the user of this API to batch-process keys. Note that this works only when deleting keys, as the same count keys are returned on each call unless removed.

The main usage of this command is during rehashing of cluster slots from one node to another. The way the rehashing is performed is exposed in the Valkey Cluster specification, or in a more simple to digest form, as an appendix of the CLUSTER SETSLOT command documentation.

> CLUSTER GETKEYSINSLOT 7000 3
1) "key_39015"
2) "key_89793"
3) "key_92937"

cluster-getslotmigrations

CLUSTER GETSLOTMIGRATIONS returns an array of information about in-progress and recently completed atomic slot migrations.

Each job previously started by CLUSTER MIGRATESLOTS creates a single entry. The number of visible slot migration entries depends on the configured cluster-slot-migration-log-max-len. After the limit is reached, the oldest inactive entry is removed. Note that active slot migrations will always be visible through CLUSTER GETSLOTMIGRATIONS, even if there are more entries than the configured limit.

Information about the slot migration operations is stored in-memory and is not persisted across restarts. Slot migration entries are visible on the primary node of both the target and source shard and the replica nodes of the target shard.

The following information is reported for each slot migration entry:

Examples

Response in RESP 2

127.0.0.1:30001> CLUSTER GETSLOTMIGRATIONS
1)  1) "name"
    2) "5371b28997de6fd0bbe813ad8ebdfdf2faadb308"
    3) "operation"
    4) "EXPORT"
    5) "slot_ranges"
    6) "0-10"
    7) "target_node"
    8) "4b4f12fdfb58d5e30fef7b9ad3f1651dacbbaba9"
    9) "source_node"
   10) "93941e777e17fcbc92d4398cc957ffea888f472b"
   11) "create_time"
   12) (integer) 1754870400
   13) "last_update_time"
   14) (integer) 1754870400
   15) "last_ack_time"
   16) (integer) 1754870400
   17) "state"
   18) "success"
   19) "message"
   20) ""
   21) "cow_size"
   22) (integer) 0
   23) "remaining_repl_size"
   24) (integer) 0

Response in RESP 3

127.0.0.1:30001> CLUSTER GETSLOTMIGRATIONS
1)  1# "name" => "5371b28997de6fd0bbe813ad8ebdfdf2faadb308"
    2# "operation" => "EXPORT"
    3# "slot_ranges" => "0-10"
    4# "target_node" => "4b4f12fdfb58d5e30fef7b9ad3f1651dacbbaba9"
    5# "source_node" => "93941e777e17fcbc92d4398cc957ffea888f472b"
    6# "create_time" => (integer) 1754870400
    7# "last_update_time" => (integer) 1754870400
    8# "last_ack_time" => (integer) 1754870400
    9# "state" => "success"
   10# "message" => ""
   11# "cow_size" => (integer) 0
   12# "remaining_repl_size" => (integer) 0

cluster-help

The CLUSTER HELP command returns a helpful text describing the different subcommands.

cluster-info

CLUSTER INFO provides INFO style information about Valkey Cluster vital parameters. The following fields are always present in the reply:

cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_nodes_pfail:0
cluster_nodes_fail:0
cluster_voting_nodes_pfail:0
cluster_voting_nodes_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:2
cluster_stats_messages_sent:1483972
cluster_stats_messages_received:1483968
total_cluster_links_buffer_limit_exceeded:0

The following message-related fields may be included in the reply if the value is not 0: Each message type includes statistics on the number of messages sent and received. Here are the explanation of these fields: ]

More information about the Current Epoch and Config Epoch variables are available in the Valkey Cluster specification document.

cluster-keyslot

Returns an integer identifying the hash slot the specified key hashes to. This command is mainly useful for debugging and testing, since it exposes via an API the underlying Valkey implementation of the hashing algorithm. Example use cases for this command:

  1. Client libraries may use Valkey in order to test their own hashing algorithm, generating random keys and hashing them with both their local implementation and using Valkey CLUSTER KEYSLOT command, then checking if the result is the same.
  2. Humans may use this command in order to check what is the hash slot, and then the associated Valkey Cluster node, responsible for a given key.

Example

> CLUSTER KEYSLOT somekey
(integer) 11058
> CLUSTER KEYSLOT foo{hash_tag}
(integer) 2515
> CLUSTER KEYSLOT bar{hash_tag}
(integer) 2515

Note that the command implements the full hashing algorithm, including support for hash tags, that is the special property of Valkey Cluster key hashing algorithm, of hashing just what is between { and } if such a pattern is found inside the key name, in order to force multiple keys to be handled by the same node.

cluster-links

Each node in a Valkey Cluster maintains a pair of long-lived TCP link with each peer in the cluster: One for sending outbound messages towards the peer and one for receiving inbound messages from the peer.

Examples

The following is an example output:

Each map is composed of the following attributes of the corresponding cluster link and their values:

cluster-meet

CLUSTER MEET is used in order to connect different Valkey nodes with cluster support enabled, into a working cluster.

The basic idea is that nodes by default don't trust each other, and are considered unknown, so that it is unlikely that different cluster nodes will mix into a single one because of system administration errors or network addresses modifications.

So in order for a given node to accept another one into the list of nodes composing a Valkey Cluster, there are only two ways:

  1. The system administrator sends a CLUSTER MEET command to force a node to meet another one.
  2. An already known node sends a list of nodes in the gossip section that we are not aware of. If the receiving node trusts the sending node as a known node, it will process the gossip section and send a handshake to the nodes that are still not known.

Note that Valkey Cluster needs to form a full mesh (each node is connected with each other node), but in order to create a cluster, there is no need to send all the CLUSTER MEET commands needed to form the full mesh. What matter is to send enough CLUSTER MEET messages so that each node can reach each other node through a chain of known nodes. Thanks to the exchange of gossip information in heartbeat packets, the missing links will be created.

Another example: if we imagine a cluster formed of the following four nodes called A, B, C and D, we may send just the following set of commands to A:

  1. CLUSTER MEET B-ip B-port
  2. CLUSTER MEET C-ip C-port
  3. CLUSTER MEET D-ip D-port

As a side effect of A knowing and being known by all the other nodes, it will send gossip sections in the heartbeat packets that will allow each other node to create a link with each other one, forming a full mesh in a matter of seconds, even if the cluster is large.

Moreover CLUSTER MEET does not need to be reciprocal. If I send the command to A in order to join B, I don't need to also send it to B in order to join A.

If the optional cluster_bus_port argument is not provided, the default of port + 10000 will be used.

Implementation details: MEET and PING packets

When a given node receives a CLUSTER MEET message, the node specified in the command still does not know the node we sent the command to. So in order for the node to force the receiver to accept it as a trusted node, it sends a MEET packet instead of a PING packet. The two packets have exactly the same format, but the former forces the receiver to acknowledge the node as trusted.

cluster-migrateslots

CLUSTER MIGRATESLOTS initiates an asynchronous migration of the designated slot range(s) to the specified target node using atomic slot migration.

This command allows for many slot ranges in a single migration through repeated start and end slot pairs within the SLOTSRANGE block. It also supports multiple migrations in one command, through repeated SLOTSRANGE and NODE blocks. For example:

CLUSTER MIGRATESLOTS SLOTSRANGE 0 9 20 29 NODE <target A> SLOTSRANGE 10 19 NODE <target B>

Initiates two slot migration jobs, one to <target A> with 20 slots (0-9 inclusive, 20-29 inclusive) and another to <target B> with 10 slots (10-19 inclusive).

OK is returned if all slot migrations are successfully initiated, otherwise an error message is returned and no slot migrations are initiated.

To check on the progress of the slot migration, use the CLUSTER GETSLOTMIGRATIONS command.

To cancel the slot migration jobs, use the CLUSTER CANCELSLOTMIGRATIONS command.

Because slot migrations may move keys belonging to any database, the caller must have ACL access to all databases (the alldbs rule). See database permissions.

cluster-myid

Returns the node's id.

The CLUSTER MYID command returns the unique, auto-generated identifier that is associated with the connected cluster node.

cluster-myshardid

Returns the node's shard id.

The CLUSTER MYSHARDID command returns the unique, auto-generated identifier that is associated with the shard to which the connected cluster node belongs.

cluster-nodes

Each node in a Valkey Cluster has its view of the current cluster configuration, given by the set of known nodes, the state of the connection we have with such nodes, their flags, properties and assigned slots, and so forth.

CLUSTER NODES provides all this information, that is, the current cluster configuration of the node we are contacting, in a serialization format which happens to be exactly the same as the one used by the Valkey Cluster itself in order to store on disk the cluster state (however the on disk cluster state has a few additional info appended at the end).

Note that normally clients willing to fetch the map between Cluster hash slots and node addresses should use CLUSTER SLOTS instead. CLUSTER NODES, that provides more information, should be used for administrative tasks, debugging, and configuration inspections. It is also used by valkey-cli in order to manage a cluster.

Serialization format

The output of the command is just a space-separated CSV string, where each line represents a node in the cluster. The following is an example of output on Valkey 7.2.4.

07c37dfeb235213a872192d90877d0cd55635b91 127.0.0.1:30004@31004,hostname4 slave e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 0 1426238317239 4 connected
67ed2db8d677e59ec4a4cefb06858cf2a1a89fa1 127.0.0.1:30002@31002,hostname2 master - 0 1426238316232 2 connected 5461-10922
292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 127.0.0.1:30003@31003,hostname3 master - 0 1426238318243 3 connected 10923-16383
6ec23923021cf3ffec47632106199cb7f496ce01 127.0.0.1:30005@31005,hostname5 slave 67ed2db8d677e59ec4a4cefb06858cf2a1a89fa1 0 1426238316232 5 connected
824fe116063bc5fcf9f4ffd895bc17aee7731ac3 127.0.0.1:30006@31006,hostname6 slave 292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 0 1426238317741 6 connected
e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 127.0.0.1:30001@31001,hostname1 myself,master - 0 0 1 connected 0-5460

Each line is composed of the following fields:

<id> <ip:port@cport[,hostname]> <flags> <master> <ping-sent> <pong-recv> <config-epoch> <link-state> <slot> <slot> ... <slot>

The meaning of each field is the following:

  1. id: The node ID, a 40-character globally unique string generated when a node is created and never changed again (unless CLUSTER RESET HARD is used).
  2. ip:port@cport: The node address that clients should contact to run queries, along with the used cluster bus port. :0@0 can be expected when the address is no longer known for this node ID, hence flagged with noaddr. Note that ip can be an IPv6 address, which can contain multiple colons. Here, an IPv6 address is not enclosed in square brackets as it would be in other contexts such as URIs. To properly split the ip:port@cport into ip and port@cport, you need to locate the last colon.
  3. hostname: A human readable string that can be configured via the cluster-annouce-hostname setting. The max length of the string is 256 characters, excluding the null terminator. The name can contain ASCII alphanumeric characters, '-', and '.' only.
  4. flags: A list of comma separated flags: myself, master, slave, fail?, fail, handshake, noaddr, nofailover, noflags. Flags are explained below.
  5. master: If the node is a replica, and the primary is known, the primary node ID, otherwise the "-" character.
  6. ping-sent: Unix time at which the currently active ping was sent, or zero if there are no pending pings, in milliseconds.
  7. pong-recv: Unix time the last pong was received, in milliseconds.
  8. config-epoch: The configuration epoch (or version) of the current node (or of the current primary if the node is a replica). Each time there is a failover, a new, unique, monotonically increasing configuration epoch is created. If multiple nodes claim to serve the same hash slots, the one with the higher configuration epoch wins.
  9. link-state: The state of the link used for the node-to-node cluster bus. Use this link to communicate with the node. Can be connected or disconnected.
  10. slot: A hash slot number or range. Starting from argument number 9, but there may be up to 16384 entries in total (limit never reached). This is the list of hash slots served by this node. If the entry is just a number, it is parsed as such. If it is a range, it is in the form start-end, and means that the node is responsible for all the hash slots from start to end including the start and end values.

Flags are:

Notes on published config epochs

Replicas broadcast their primary's config epochs (in order to get an UPDATE message if they are found to be stale), so the real config epoch of the replica (which is meaningless more or less, since they don't serve hash slots) can be only obtained checking the node flagged as myself, which is the entry of the node we are asking to generate CLUSTER NODES output. The other replicas epochs reflect what they publish in heartbeat packets, which is, the configuration epoch of the primaries they are currently replicating.

Special slot entries

Normally hash slots associated to a given node are in one of the following formats, as already explained above:

  1. Single number: 3894
  2. Range: 3900-4000

However node hash slots can be in a special state, used in order to communicate errors after a node restart (mismatch between the keys in the AOF/RDB file, and the node hash slots configuration), or when there is a resharding operation in progress. This two states are importing and migrating.

The meaning of the two states is explained in the Valkey Specification, however the gist of the two states is the following:

Importing and migrating slots are emitted in the CLUSTER NODES output as follows:

The following are a few examples of importing and migrating slots:

Note that the format does not have any space, so CLUSTER NODES output format is plain CSV with space as separator even when these special slots are emitted. However a complete parser for the format should be able to handle them.

Note that:

  1. Migration and importing slots are only added to the node flagged as myself. This information is local to a node, for its own slots.
  2. Importing and migrating slots are provided as additional info. If the node has a given hash slot assigned, it will be also a plain number in the list of hash slots, so clients that don't have a clue about hash slots migrations can just skip these special fields.

NOTE: If not for backward compatibility, the Valkey project no longer uses the words "master" and "slave". Unfortunately, in the given commands these words are part of the protocol, so we'll be able to remove such occurrences only when this API is naturally deprecated.

cluster-replicas

The command provides a list of replica nodes replicating from the specified primary node. The list is provided in the same format used by CLUSTER NODES (please refer to its documentation for the specification of the format).

The command will fail if the specified node is not known or if it is not a primary according to the node table of the node receiving the command.

Note that if a replica is added, moved, or removed from a given primary node, and we ask CLUSTER REPLICAS to a node that has not yet received the configuration update, it may show stale information. However eventually (in a matter of seconds if there are no network partitions) all the nodes will agree about the set of nodes associated with a given primary.

cluster-replicate

The command reconfigures a node as a replica of the specified primary. If the node receiving the command is an empty primary, as a side effect of the command, the node role is changed from primary to replica.

Once a node is turned into the replica of another primary node, there is no need to inform the other cluster nodes about the change: heartbeat packets exchanged between nodes will propagate the new configuration automatically.

A replica will always accept the command, assuming that:

  1. The specified node ID exists in its nodes table.
  2. The specified node ID does not identify the instance we are sending the command to.
  3. The specified node ID is a primary.

If the node receiving the command is not already a replica, but is a primary, the command will only succeed, and the node will be converted into a replica, only if the following additional conditions are met:

  1. The node is not serving any hash slots.
  2. The node is empty, no keys are stored at all in the key space.

If the command succeeds the new replica will immediately try to contact its primary in order to replicate from it.

cluster-reset

Reset a Valkey Cluster node, in a more or less drastic way depending on the reset type, that can be hard or soft. Note that this command does not work for primaries if they hold one or more keys, in that case to completely reset a primary node keys must be removed first, e.g. by using FLUSHALL first, and then CLUSTER RESET.

Effects on the node:

  1. All the other nodes in the cluster are forgotten.
  2. All the assigned / open slots are reset, so the slots-to-nodes mapping is totally cleared.
  3. If the node is a replica it is turned into an (empty) primary. Its dataset is flushed, so at the end the node will be an empty primary.
  4. Hard reset only: a new Node ID is generated.
  5. Hard reset only: currentEpoch and configEpoch vars are set to 0.
  6. The new configuration is persisted on disk in the node cluster configuration file.

This command is mainly useful to re-provision a Valkey Cluster node in order to be used in the context of a new, different cluster. The command is also extensively used by the Valkey Cluster testing framework in order to reset the state of the cluster every time a new test unit is executed.

If no reset type is specified, the default is soft.

cluster-saveconfig

Forces a node to save the nodes.conf configuration on disk. Before returning, the command calls fsync(2) in order to make sure the configuration is flushed on the computer disk.

This command is mainly used in the event a nodes.conf node state file gets lost / deleted for some reason, and we want to generate it again from scratch. It can also be useful in case of mundane alterations of a node cluster configuration via the CLUSTER command in order to ensure the new configuration is persisted on disk, however all the commands should normally be able to auto schedule to persist the configuration on disk when it is important to do so for the correctness of the system in the event of a restart.

cluster-set-config-epoch

This command sets a specific config epoch in a fresh node. It only works when:

  1. The nodes table of the node is empty.
  2. The node current config epoch is zero.

These prerequisites are needed since usually, manually altering the configuration epoch of a node is unsafe, we want to be sure that the node with the higher configuration epoch value (that is the last that failed over) wins over other nodes in claiming the hash slots ownership.

However there is an exception to this rule, and it is when a new cluster is created from scratch. Valkey Cluster config epoch collision resolution algorithm can deal with new nodes all configured with the same configuration at startup, but this process is slow and should be the exception, only to make sure that whatever happens, two more nodes eventually always move away from the state of having the same configuration epoch.

So, using CLUSTER SET-CONFIG-EPOCH, when a new cluster is created, we can assign a different progressive configuration epoch to each node before joining the cluster together.

cluster-setslot

CLUSTER SETSLOT is responsible for changing the state of a hash slot in the receiving node in different ways. It is part of the legacy mechanism for cluster resharding.

Note: For live resharding, the newer atomic slot migration mechanism using CLUSTER MIGRATESLOTS is recommended as it is faster, more reliable, and has less impact on client applications.

CLUSTER SETSLOT can, depending on the subcommand used:

  1. MIGRATING subcommand: Set a hash slot in migrating state.
  2. IMPORTING subcommand: Set a hash slot in importing state.
  3. STABLE subcommand: Clear any importing / migrating state from hash slot.
  4. NODE subcommand: Bind the hash slot to a different node.

The command with its set of subcommands is useful in order to start and end cluster live resharding operations, which are accomplished by setting a hash slot in migrating state in the source node, and importing state in the destination node.

Each subcommand is documented below. At the end you'll find a description of how live resharding is performed using this command and other related commands.

CLUSTER SETSLOT <slot> MIGRATING <destination-node-id>

This subcommand sets a slot to migrating state. In order to set a slot in this state, the node receiving the command must be the hash slot owner, otherwise an error is returned.

When a slot is set in migrating state, the node changes behavior in the following way:

  1. If a command is received about an existing key, the command is processed as usually.
  2. If a command is received about a key that does not exists, an ASK redirection is emitted by the node, asking the client to retry only that specific query into destination-node. In this case the client should not update its hash slot to node mapping.
  3. If the command contains multiple keys, in case none exist, the behavior is the same as point 2, if all exist, it is the same as point 1, however if only a partial number of keys exist, the command emits a TRYAGAIN error in order for the keys interested to finish being migrated to the target node, so that the multi keys command can be executed.

CLUSTER SETSLOT <slot> IMPORTING <source-node-id>

This subcommand is the reverse of MIGRATING, and prepares the destination node to import keys from the specified source node. The command only works if the node is not already owner of the specified hash slot.

When a slot is set in importing state, the node changes behavior in the following way:

  1. Commands about this hash slot are refused and a MOVED redirection is generated as usually, but in the case the command follows an ASKING command, in this case the command is executed.

In this way when a node in migrating state generates an ASK redirection, the client contacts the target node, sends ASKING, and immediately after sends the command. This way commands about non-existing keys in the old node or keys already migrated to the target node are executed in the target node, so that:

  1. New keys are always created in the target node. During a hash slot migration we'll have to move only old keys, not new ones.
  2. Commands about keys already migrated are correctly processed in the context of the node which is the target of the migration, the new hash slot owner, in order to guarantee consistency.
  3. Without ASKING the behavior is the same as usually. This guarantees that clients with a broken hash slots mapping will not write for error in the target node, creating a new version of a key that has yet to be migrated.

CLUSTER SETSLOT <slot> STABLE

This subcommand just clears migrating / importing state from the slot. It is mainly used to fix a cluster stuck in a wrong state by valkey-cli --cluster fix. Normally the two states are cleared automatically at the end of the migration using the SETSLOT ... NODE ... subcommand as explained in the next section.

CLUSTER SETSLOT <slot> NODE <node-id>

The NODE subcommand is the one with the most complex semantics. It associates the hash slot with the specified node, however the command works only in specific situations and has different side effects depending on the slot state. The following is the set of pre-conditions and side effects of the command:

  1. If the current hash slot owner is the node receiving the command, but for effect of the command the slot would be assigned to a different node, the command will return an error if there are still keys for that hash slot in the node receiving the command.
  2. If the slot is in migrating state, the state gets cleared when the slot is assigned to another node.
  3. If the slot was in importing state in the node receiving the command, and the command assigns the slot to this node (which happens in the target node at the end of the resharding of a hash slot from one node to another), the command has the following side effects: A) the importing state is cleared. B) If the node config epoch is not already the greatest of the cluster, it generates a new one and assigns the new config epoch to itself. This way its new hash slot ownership will win over any past configuration created by previous failovers or slot migrations.

It is important to note that step 3 is the only time when a Valkey Cluster node will create a new config epoch without agreement from other nodes. This only happens when a manual configuration is operated. However it is impossible that this creates a non-transient setup where two nodes have the same config epoch, since Valkey Cluster uses a config epoch collision resolution algorithm.

Valkey Cluster live resharding explained

The CLUSTER SETSLOT command is an important piece used by Valkey Cluster in order to migrate all the keys contained in one hash slot from one node to another. This is how the migration is orchestrated, with the help of other commands as well. We'll call the node that has the current ownership of the hash slot the source node, and the node where we want to migrate the destination node.

  1. Set the destination node slot to importing state using CLUSTER SETSLOT <slot> IMPORTING <source-node-id>.
  2. Set the source node slot to migrating state using CLUSTER SETSLOT <slot> MIGRATING <destination-node-id>.
  3. Get keys from the source node with CLUSTER GETKEYSINSLOT command and move them into the destination node using the MIGRATE command.
  4. Send CLUSTER SETSLOT <slot> NODE <destination-node-id> to the destination node.
  5. Send CLUSTER SETSLOT <slot> NODE <destination-node-id> to the source node.
  6. Send CLUSTER SETSLOT <slot> NODE <destination-node-id> to the other primary nodes (optional).

Notes:

cluster-shards

CLUSTER SHARDS returns details about the shards of the cluster. A shard is defined as a collection of nodes that serve the same set of slots and that replicate from each other. A shard may only have a single primary at a given time, but may have multiple or no replicas. It is possible for a shard to not be serving any slots while still having replicas.

The command is suitable to be used by Valkey Cluster client libraries in order to understand the topology of the cluster. A client should issue this command on startup in order to retrieve the map associating cluster hash slots with actual node information. This map should be used to direct commands to the node that is likely serving the slot associated with a given command. In the event the command is sent to the wrong node, in that it received a '-MOVED' redirect, this command can then be used to update the topology of the cluster.

The command returns an array of shards, with each shard containing three fields, 'slots', 'nodes' and 'id'.

The 'slots' field is a list of slot ranges served by this shard, stored as pair of integers representing the inclusive start and end slots of the ranges. For example, if a node owns the slots 1, 2, 3, 5, 7, 8 and 9, the slots ranges would be stored as [1-3], [5-5], [7-9]. The slots field would therefore be represented by the following list of integers.

1) 1) "slots"
   2) 1) (integer) 1
      2) (integer) 3
      3) (integer) 5
      4) (integer) 5
      5) (integer) 7
      6) (integer) 9

The 'nodes' field contains a list of all nodes within the shard. Each individual node is a map of attributes that describe the node. Some attributes are optional and more attributes may be added in the future. The current list of attributes:

The endpoint, along with the port, defines the location that clients should use to send requests for a given slot. A NULL value for the endpoint indicates the node has an unknown endpoint and the client should connect to the same endpoint it used to send the CLUSTER SHARDS command but with the port returned from the command. This unknown endpoint configuration is useful when the Valkey nodes are behind a load balancer that Valkey doesn't know the endpoint of. Which endpoint is set is determined by the cluster-preferred-endpoint-type config. An empty string "" is another abnormal value of the endpoint field, as well as for the ip field, which is returned if the node doesn't know its own IP address. This can happen in a cluster that consists of only one node or the node has not yet been joined with the rest of the cluster. The value ? is displayed if the node is incorrectly configured to use announced hostnames but no hostname is configured using cluster-announce-hostname. Clients may treat the empty string in the same way as NULL, that is the same endpoint it used to send the current command to, while "?" should be treated as an unknown node, not necessarily the same node as the one serving the current command.

The 'id' field is the unique id of the shard, which is randomly generated and 40 characters long.

Examples

> CLUSTER SHARDS
1) 1) "slots"
   2) 1) (integer) 0
      2) (integer) 5460
   3) "nodes"
   4) 1)  1) "id"
          2) "e10b7051d6bf2d5febd39a2be297bbaea6084111"
          3) "port"
          4) (integer) 30001
          5) "ip"
          6) "127.0.0.1"
          7) "endpoint"
          8) "127.0.0.1"
          9) "role"
         10) "master"
         11) "replication-offset"
         12) (integer) 72156
         13) "health"
         14) "online"
         15) "availability-zone"
         16) "zone-a"
      2)  1) "id"
          2) "1901f5962d865341e81c85f9f596b1e7160c35ce"
          3) "port"
          4) (integer) 30006
          5) "ip"
          6) "127.0.0.1"
          7) "endpoint"
          8) "127.0.0.1"
          9) "role"
         10) "replica"
         11) "replication-offset"
         12) (integer) 72156
         13) "health"
         14) "online"
         15) "availability-zone"
         16) "zone-a"
   5) "id"
   6) "cd7688ca959bf54a32569ccf260b26715b82a6e3"         
2) 1) "slots"
   2) 1) (integer) 10923
      2) (integer) 16383
   3) "nodes"
   4) 1)  1) "id"
          2) "fd20502fe1b32fc32c15b69b0a9537551f162f1f"
          3) "port"
          4) (integer) 30003
          5) "ip"
          6) "127.0.0.1"
          7) "endpoint"
          8) "127.0.0.1"
          9) "role"
         10) "master"
         11) "replication-offset"
         12) (integer) 72156
         13) "health"
         14) "online"
         15) "availability-zone"
         16) "zone-a"
      2)  1) "id"
          2) "6daa25c08025a0c7e4cc0d1ab255949ce6cee902"
          3) "port"
          4) (integer) 30005
          5) "ip"
          6) "127.0.0.1"
          7) "endpoint"
          8) "127.0.0.1"
          9) "role"
         10) "replica"
         11) "replication-offset"
         12) (integer) 72156
         13) "health"
         14) "online"
         15) "availability-zone"
         16) "zone-a"
   5) "id"
   6) "0d77234c440a6b05c2d77d1b9f37ac63585fc747"         
3) 1) "slots"
   2) 1) (integer) 5461
      2) (integer) 10922
   3) "nodes"
   4) 1)  1) "id"
          2) "a4a3f445ead085eb3eb9ee7d8c644ec4481ec9be"
          3) "port"
          4) (integer) 30002
          5) "ip"
          6) "127.0.0.1"
          7) "endpoint"
          8) "127.0.0.1"
          9) "role"
         10) "master"
         11) "replication-offset"
         12) (integer) 72156
         13) "health"
         14) "online"
         15) "availability-zone"
         16) "zone-a"
      2)  1) "id"
          2) "da6d5847aa019e9b9d2a8aa24a75f856fd3456cc"
          3) "port"
          4) (integer) 30004
          5) "ip"
          6) "127.0.0.1"
          7) "endpoint"
          8) "127.0.0.1"
          9) "role"
         10) "replica"
         11) "replication-offset"
         12) (integer) 72156
         13) "health"
         14) "online"
         15) "availability-zone"
         16) "zone-a"
   5) "id"
   6) "a96f023185ea6d7f5e9a0d6ada6f112741217e6a"         

cluster-slaves

A note about the word slave used in this man page and command name: the Valkey project no longer uses the words "master" and "slave". Please use the new command CLUSTER REPLICAS. The command CLUSTER SLAVES will continue to work for backward compatibility.

The command provides a list of replica nodes replicating from the specified primary node. The list is provided in the same format used by CLUSTER NODES (please refer to its documentation for the specification of the format).

The command will fail if the specified node is not known or if it is not a primary according to the node table of the node receiving the command.

Note that if a replica is added, moved, or removed from a given primary node, and we ask CLUSTER SLAVES to a node that has not yet received the configuration update, it may show stale information. However eventually (in a matter of seconds if there are no network partitions) all the nodes will agree about the set of nodes associated with a given primary.

cluster-slot-stats

Returns an array of slot usage statistics for slots assigned to the current shard. The command is suitable for Valkey Cluster users aiming to assess general slot usage trends, identify hot / cold slots, migrate slots for a balanced cluster workload, and / or re-write application logic to better utilize slots.

The following statistics are supported:

Note: By default, only key-count is returned. To enable cpu-usec, network-bytes-in, and network-bytes-out statistics, set cluster-slot-stats-enabled yes in the configuration.

Options

Examples

Response in RESP2

For ORDERBY:

> CLUSTER SLOT-STATS ORDERBY KEY-COUNT LIMIT 2 DESC
1) 1) (integer) 12426
   2) 1) "key-count"
      2) (integer) 45
      3) "cpu-usec"
      4) (integer) 0
      5) "network-bytes-in"
      6) (integer) 0
      7) "network-bytes-out"
      8) (integer) 0
2) 1) (integer) 13902
   2) 1) "key-count"
      2) (integer) 20
      3) "cpu-usec"
      4) (integer) 0
      5) "network-bytes-in"
      6) (integer) 0
      7) "network-bytes-out"
      8) (integer) 0

For SLOTSRANGE:

> CLUSTER SLOT-STATS SLOTSRANGE 0 1
1) 1) (integer) 0
   2) 1) "key-count"
      2) (integer) 0
      3) "cpu-usec"
      4) (integer) 0
      5) "network-bytes-in"
      6) (integer) 0
      7) "network-bytes-out"
      8) (integer) 0
2) 1) (integer) 1
   2) 1) "key-count"
      2) (integer) 0
      3) "cpu-usec"
      4) (integer) 0
      5) "network-bytes-in"
      6) (integer) 0
      7) "network-bytes-out"
      8) (integer) 0

Response in RESP3

For ORDERBY:

> CLUSTER SLOT-STATS ORDERBY KEY-COUNT LIMIT 2 DESC
1) 1) (integer) 12426
   2) 1# "key-count" => (integer) 45
      2# "cpu-usec" => (integer) 0
      3# "network-bytes-in" => (integer) 0
      4# "network-bytes-out" => (integer) 0
2) 1) (integer) 13902
   2) 1# "key-count" => (integer) 20
      2# "cpu-usec" => (integer) 0
      3# "network-bytes-in" => (integer) 0
      4# "network-bytes-out" => (integer) 0

For SLOTSRANGE:

> CLUSTER SLOT-STATS SLOTSRANGE 0 1
1) 1) (integer) 0
   2) 1# "key-count" => (integer) 0
      2# "cpu-usec" => (integer) 0
      3# "network-bytes-in" => (integer) 0
      4# "network-bytes-out" => (integer) 0
2) 1) (integer) 1
   2) 1# "key-count" => (integer) 0
      2# "cpu-usec" => (integer) 0
      3# "network-bytes-in" => (integer) 0
      4# "network-bytes-out" => (integer) 0

cluster-slots

CLUSTER SLOTS returns details about which cluster slots map to which Valkey instances. The command is suitable to be used by Valkey Cluster client libraries implementations in order to retrieve (or update when a redirection is received) the map associating cluster hash slots with actual nodes network information, so that when a command is received, it can be sent to what is likely the right instance for the keys specified in the command.

The networking information for each node is an array containing the following elements:

The preferred endpoint, along with the port, defines the location that clients should use to send requests for a given slot. A NULL value for the endpoint indicates the node has an unknown endpoint and the client should connect to the same endpoint it used to send the CLUSTER SLOTS command but with the port returned from the command. This unknown endpoint configuration is useful when the Valkey nodes are behind a load balancer that Valkey doesn't know the endpoint of. Which endpoint is set as preferred is determined by the cluster-preferred-endpoint-type config. An empty string "" is another abnormal value of the endpoint field, as well as for the ip field, which is returned if the node doesn't know its own IP address. This can happen in a cluster that consists of only one node or the node has not yet been joined with the rest of the cluster. The value ? is displayed if the node is incorrectly configured to use announced hostnames but no hostname is configured using cluster-announce-hostname. Clients may treat the empty string in the same way as NULL, that is the same endpoint it used to send the current command to, while "?" should be treated as an unknown node, not necessarily the same node as the one serving the current command.

Additional networking metadata is provided as a map on the fourth argument for each node. The following networking metadata may be returned:

Nested Result Array

Each nested result is:

Each result includes all active replicas of the primary instance for the listed slot range. Failed replicas are not returned.

The command response is deterministic across all nodes in a cluster, which means that if two nodes return the same response they have the same view of the cluster. Primaries are ordered by the slots they serve and then replicas are ordered lexicographically by the node-id they were assigned by the cluster. The third nested reply is guaranteed to be the networking information of the primary instance for the slot range. All networking information after the third nested reply are replicas of the primary.

If a cluster instance has non-contiguous slots (e.g. 1-400,900,1800-6000) then primary and replica networking information results will be duplicated for each top-level slot range reply.

> CLUSTER SLOTS
1) 1) (integer) 0
   2) (integer) 5460
   3) 1) "127.0.0.1"
      2) (integer) 30001
      3) "09dbe9720cda62f7865eabc5fd8857c5d2678366"
      4) 1) hostname
         2) "host-1.valkey.example.com"
         3) availability-zone
         4) "zone-a"
   4) 1) "127.0.0.1"
      2) (integer) 30004
      3) "821d8ca00d7ccf931ed3ffc7e3db0599d2271abf"
      4) 1) hostname
         2) "host-2.valkey.example.com"
         3) availability-zone
         4) "zone-a"
2) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "127.0.0.1"
      2) (integer) 30002
      3) "c9d93d9f2c0c524ff34cc11838c2003d8c29e013"
      4) 1) hostname
         2) "host-3.valkey.example.com"
         3) availability-zone
         4) "zone-a"
   4) 1) "127.0.0.1"
      2) (integer) 30005
      3) "faadb3eb99009de4ab72ad6b6ed87634c7ee410f"
      4) 1) hostname
         2) "host-4.valkey.example.com"
         3) availability-zone
         4) "zone-a"
3) 1) (integer) 10923
   2) (integer) 16383
   3) 1) "127.0.0.1"
      2) (integer) 30003
      3) "044ec91f325b7595e76dbcb18cc688b6a5b434a1"
      4) 1) hostname
         2) "host-5.valkey.example.com"
         3) availability-zone
         4) "zone-a"
   4) 1) "127.0.0.1"
      2) (integer) 30006
      3) "58e6e48d41228013e5d9c1c37c5060693925e97e"
      4) 1) hostname
         2) "host-6.valkey.example.com"
         3) availability-zone
         4) "zone-a"

Warning: In future versions there could be more elements describing the node better. In general a client implementation should just rely on the fact that certain parameters are at fixed positions as specified, but more parameters may follow and should be ignored. Similarly a client library should try if possible to cope with the fact that older versions may just have the primary endpoint and port parameter.

cluster-syncslots

Internal command to allow navigation of the atomic slot migration state machine.

For more information about atomic slot migration in Valkey please check the atomic slot migration page.

cluster

This is a container command for Valkey Cluster commands.

To see the list of available commands you can call CLUSTER HELP.

clusterscan

CLUSTERSCAN iterates over keys across a Valkey Cluster. It walks through every hash slot in the cluster, one slot at a time.

Similar to SCAN, it is cursor-based. You start by passing 0 as the cursor and keep calling until the returned cursor is 0 again. The cursor format is fingerprint-{hashtag}-localcursor. The fingerprint is an opaque string that identifies how the node will return cursor, which currently includes information about the engine version and the hash-seed config value. Mismatches in the fingerprint will result in the cursor restarting the current slot. The hash tag represents the current slot (e.g., {06S}), so cluster-aware clients will route each call to the right node automatically. The local cursor helps resume the scan from where it left off.

127.0.0.1:6379> CLUSTERSCAN 0
1) "0-{06S}-0"
2) (empty list or set)
127.0.0.1:6379> CLUSTERSCAN 0-{06S}-0
1) "0B3a21-{06S}-96"
2) 1) "key:1"
   2) "key:2"
   3) "key:3"
127.0.0.1:6379> CLUSTERSCAN 0B3a21-{06S}-96
1) "0-{Qi}-0"
2) 1) "key:4"

In this example, the first call returns an initial cursor for slot 0 with no keys. The next call scans through slot 0 and returns keys. Once slot 0 is done, the cursor moves on to slot 1 (you can see the hash tag change from {06S} to {Qi}). Since the cursor carries the hash tag, the client naturally routes the next call to whichever node owns slot 1. This continues until all slots have been visited and the cursor comes back as 0.

The SLOT option

By default CLUSTERSCAN goes through all slots from 0 to 16383. If you only care about keys in a particular slot, pass the SLOT option:

127.0.0.1:6379> CLUSTERSCAN 0 SLOT 0
1) "0-{06S}-0"
2) (empty list or set)
127.0.0.1:6379> CLUSTERSCAN 0-{06S}-0 SLOT 0
1) "0B3a21-{06S}-64"
2) 1) "key_in_slot0:1"

With SLOT, the scan stays within that slot and returns 0 when it's done rather than advancing to the next one. This also makes it possible to run scans in parallel by issuing concurrent CLUSTERSCAN calls for different slots. If the cursor already points to a different slot than the SLOT argument, you'll get an error. You can only specify SLOT once per call.

MATCH, COUNT and TYPE options

These work the same way as in SCAN. MATCH filters by a glob-style pattern, COUNT hints how many keys to return per call (default 10), and TYPE filters by data type.

Handling topology changes

CLUSTERSCAN is designed to keep working when the cluster topology changes mid-scan:

When all nodes share the same hash-seed, the fingerprint stays consistent across failovers and resharding, so cursors remain valid without restarting.

Guarantees

CLUSTERSCAN gives the same guarantees as SCAN:

Return value

An array with two elements: the cursor to pass in the next call, and an array of key names.

command-count

Returns the total number of commands in this Valkey server.

Examples

127.0.0.1:6379> COMMAND COUNT
(integer) 241

command-docs

Return documentary information about commands.

By default, the reply includes all of the server's commands. You can use the optional command-name argument to specify the names of one or more commands.

The reply includes a map for each returned command. The following keys may be included in the mapped reply:

Examples

127.0.0.1:6379> COMMAND DOCS SET
1) "set"
2)  1) "summary"
    2) "Sets the string value of a key, ignoring its type. The key is created if it doesn't exist."
    3) "since"
    4) "1.0.0"
    5) "group"
    6) "string"
    7) "complexity"
    8) "O(1)"
    9) "history"
   10) 1) 1) "2.6.12"
          2) "Added the `EX`, `PX`, `NX` and `XX` options."
       2) 1) "6.0.0"
          2) "Added the `KEEPTTL` option."
       3) 1) "6.2.0"
          2) "Added the `GET`, `EXAT` and `PXAT` option."
       4) 1) "7.0.0"
          2) "Allowed the `NX` and `GET` options to be used together."
   11) "arguments"
   12) 1) 1) "name"
          2) "key"
          3) "type"
          4) "key"
          5) "display_text"
          6) "key"
          7) "key_spec_index"
          8) (integer) 0
       2) 1) "name"
          2) "value"
          3) "type"
          4) "string"
          5) "display_text"
          6) "value"
       3)  1) "name"
           2) "condition"
           3) "type"
           4) "oneof"
           5) "since"
           6) "2.6.12"
           7) "flags"
           8) 1) optional
           9) "arguments"
          10) 1) 1) "name"
                 2) "nx"
                 3) "type"
                 4) "pure-token"
                 5) "display_text"
                 6) "nx"
                 7) "token"
                 8) "NX"
              2) 1) "name"
                 2) "xx"
                 3) "type"
                 4) "pure-token"
                 5) "display_text"
                 6) "xx"
                 7) "token"
                 8) "XX"
       4)  1) "name"
           2) "get"
           3) "type"
           4) "pure-token"
           5) "display_text"
           6) "get"
           7) "token"
           8) "GET"
           9) "since"
          10) "6.2.0"
          11) "flags"
          12) 1) optional
       5) 1) "name"
          2) "expiration"
          3) "type"
          4) "oneof"
          5) "flags"
          6) 1) optional
          7) "arguments"
          8) 1)  1) "name"
                 2) "seconds"
                 3) "type"
                 4) "integer"
                 5) "display_text"
                 6) "seconds"
                 7) "token"
                 8) "EX"
                 9) "since"
                10) "2.6.12"
             2)  1) "name"
                 2) "milliseconds"
                 3) "type"
                 4) "integer"
                 5) "display_text"
                 6) "milliseconds"
                 7) "token"
                 8) "PX"
                 9) "since"
                10) "2.6.12"
             3)  1) "name"
                 2) "unix-time-seconds"
                 3) "type"
                 4) "unix-time"
                 5) "display_text"
                 6) "unix-time-seconds"
                 7) "token"
                 8) "EXAT"
                 9) "since"
                10) "6.2.0"
             4)  1) "name"
                 2) "unix-time-milliseconds"
                 3) "type"
                 4) "unix-time"
                 5) "display_text"
                 6) "unix-time-milliseconds"
                 7) "token"
                 8) "PXAT"
                 9) "since"
                10) "6.2.0"
             5)  1) "name"
                 2) "keepttl"
                 3) "type"
                 4) "pure-token"
                 5) "display_text"
                 6) "keepttl"
                 7) "token"
                 8) "KEEPTTL"
                 9) "since"
                10) "6.0.0"

command-getkeys

Returns @array-reply of keys from a full Valkey command.

COMMAND GETKEYS is a helper command to let you find the keys from a full Valkey command.

COMMAND provides information on how to find the key names of each command (see firstkey, key specifications, and movablekeys), but in some cases it's not possible to find keys of certain commands and then the entire command must be parsed to discover some / all key names. You can use COMMAND GETKEYS or COMMAND GETKEYSANDFLAGS to discover key names directly from how Valkey parses the commands.

Examples

127.0.0.1:6379> COMMAND GETKEYS MSET a b c d e f
1) "a"
2) "c"
3) "e"
127.0.0.1:6379> COMMAND GETKEYS EVAL "not consulted" 3 key1 key2 key3 arg1 arg2 arg3 argN
1) "key1"
2) "key2"
3) "key3"
127.0.0.1:6379> COMMAND GETKEYS SORT mylist ALPHA STORE outlist
1) "mylist"
2) "outlist"

command-getkeysandflags

Returns @array-reply of keys from a full Valkey command and their usage flags.

COMMAND GETKEYSANDFLAGS is a helper command to let you find the keys from a full Valkey command together with flags indicating what each key is used for.

COMMAND provides information on how to find the key names of each command (see firstkey, key specifications, and movablekeys), but in some cases it's not possible to find keys of certain commands and then the entire command must be parsed to discover some / all key names. You can use COMMAND GETKEYS or COMMAND GETKEYSANDFLAGS to discover key names directly from how Valkey parses the commands.

Refer to key specifications for information about the meaning of the key flags.

Examples

127.0.0.1:6379> COMMAND GETKEYS MSET a b c d e f
1) "a"
2) "c"
3) "e"
127.0.0.1:6379> COMMAND GETKEYS EVAL "not consulted" 3 key1 key2 key3 arg1 arg2 arg3 argN
1) "key1"
2) "key2"
3) "key3"
127.0.0.1:6379> COMMAND GETKEYSANDFLAGS LMOVE mylist1 mylist2 left left
1) 1) "mylist1"
   2) 1) RW
      2) access
      3) delete
2) 1) "mylist2"
   2) 1) RW
      2) insert

command-help

The COMMAND HELP command returns a helpful text describing the different subcommands.

command-info

Returns @array-reply of details about multiple Valkey commands.

Same result format as COMMAND except you can specify which commands get returned.

If you request details about non-existing commands, their return position will be nil.

Examples

127.0.0.1:6379> COMMAND INFO get set eval
1)  1) "get"
    2) (integer) 2
    3) 1) readonly
       2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
       2) @string
       3) @fast
    8) (empty array)
    9) 1) 1) "flags"
          2) 1) RO
             2) access
          3) "begin_search"
          4) 1) "type"
             2) "index"
             3) "spec"
             4) 1) "index"
                2) (integer) 1
          5) "find_keys"
          6) 1) "type"
             2) "range"
             3) "spec"
             4) 1) "lastkey"
                2) (integer) 0
                3) "keystep"
                4) (integer) 1
                5) "limit"
                6) (integer) 0
   10) (empty array)
2)  1) "set"
    2) (integer) -3
    3) 1) write
       2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
       2) @string
       3) @slow
    8) (empty array)
    9) 1) 1) "notes"
          2) "RW and ACCESS due to the optional `GET` argument"
          3) "flags"
          4) 1) RW
             2) access
             3) update
             4) variable_flags
          5) "begin_search"
          6) 1) "type"
             2) "index"
             3) "spec"
             4) 1) "index"
                2) (integer) 1
          7) "find_keys"
          8) 1) "type"
             2) "range"
             3) "spec"
             4) 1) "lastkey"
                2) (integer) 0
                3) "keystep"
                4) (integer) 1
                5) "limit"
                6) (integer) 0
   10) (empty array)
3)  1) "eval"
    2) (integer) -3
    3) 1) noscript
       2) stale
       3) skip_monitor
       4) no_mandatory_keys
       5) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
       2) @scripting
    8) (empty array)
    9) 1) 1) "notes"
          2) "We cannot tell how the keys will be used so we assume the worst, RW and UPDATE"
          3) "flags"
          4) 1) RW
             2) access
             3) update
          5) "begin_search"
          6) 1) "type"
             2) "index"
             3) "spec"
             4) 1) "index"
                2) (integer) 2
          7) "find_keys"
          8) 1) "type"
             2) "keynum"
             3) "spec"
             4) 1) "keynumidx"
                2) (integer) 0
                3) "firstkey"
                4) (integer) 1
                5) "keystep"
                6) (integer) 1
   10) (empty array)
127.0.0.1:6379> COMMAND INFO foo evalsha config bar
1) (nil)
2)  1) "evalsha"
    2) (integer) -3
    3) 1) noscript
       2) stale
       3) skip_monitor
       4) no_mandatory_keys
       5) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
       2) @scripting
    8) (empty array)
    9) 1) 1) "flags"
          2) 1) RW
             2) access
             3) update
          3) "begin_search"
          4) 1) "type"
             2) "index"
             3) "spec"
             4) 1) "index"
                2) (integer) 2
          5) "find_keys"
          6) 1) "type"
             2) "keynum"
             3) "spec"
             4) 1) "keynumidx"
                2) (integer) 0
                3) "firstkey"
                4) (integer) 1
                5) "keystep"
                6) (integer) 1
   10) (empty array)
3)  1) "config"
    2) (integer) -2
    3) (empty array)
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    8) (empty array)
    9) (empty array)
   10) 1)  1) "config|rewrite"
           2) (integer) 2
           3) 1) admin
              2) noscript
              3) loading
              4) stale
           4) (integer) 0
           5) (integer) 0
           6) (integer) 0
           7) 1) @admin
              2) @slow
              3) @dangerous
           8) 1) "request_policy:all_nodes"
              2) "response_policy:all_succeeded"
           9) (empty array)
          10) (empty array)
       2)  1) "config|resetstat"
           2) (integer) 2
           3) 1) admin
              2) noscript
              3) loading
              4) stale
           4) (integer) 0
           5) (integer) 0
           6) (integer) 0
           7) 1) @admin
              2) @slow
              3) @dangerous
           8) 1) "request_policy:all_nodes"
              2) "response_policy:all_succeeded"
           9) (empty array)
          10) (empty array)
       3)  1) "config|help"
           2) (integer) 2
           3) 1) loading
              2) stale
           4) (integer) 0
           5) (integer) 0
           6) (integer) 0
           7) 1) @slow
           8) (empty array)
           9) (empty array)
          10) (empty array)
       4)  1) "config|get"
           2) (integer) -3
           3) 1) admin
              2) noscript
              3) loading
              4) stale
           4) (integer) 0
           5) (integer) 0
           6) (integer) 0
           7) 1) @admin
              2) @slow
              3) @dangerous
           8) (empty array)
           9) (empty array)
          10) (empty array)
       5)  1) "config|set"
           2) (integer) -4
           3) 1) admin
              2) noscript
              3) loading
              4) stale
           4) (integer) 0
           5) (integer) 0
           6) (integer) 0
           7) 1) @admin
              2) @slow
              3) @dangerous
           8) 1) "request_policy:all_nodes"
              2) "response_policy:all_succeeded"
           9) (empty array)
          10) (empty array)
4) (nil)

command-list

Return an array of the server's command names.

You can use the optional FILTERBY modifier to apply one of the following filters:

command

Return an array with details about every Valkey command.

The COMMAND command is introspective. Its reply describes all commands that the server can process. Valkey clients can call it to obtain the server's runtime capabilities during the handshake.

COMMAND also has several subcommands. Please refer to its subcommands for further details.

Cluster note: this command is especially beneficial for cluster-aware clients. Such clients must identify the names of keys in commands to route requests to the correct shard. Although most commands accept a single key as their first argument, there are many exceptions to this rule. You can call COMMAND and then keep the mapping between commands and their respective key specification rules cached in the client.

The reply it returns is an array with an element per command. Each element that describes a Valkey command is represented as an array by itself.

The command's array consists of a fixed number of elements. The exact number of elements in the array depends on the server's version.

  1. Name
  2. Arity
  3. Flags
  4. First key
  5. Last key
  6. Step
  7. ACL categories
  8. Tips
  9. Key specifications
  10. Subcommands

Name

This is the command's name in lowercase.

Note: Valkey command names are case-insensitive.

Arity

Arity is the number of arguments a command expects. It follows a simple pattern:

Command arity always includes the command's name itself (and the subcommand when applicable).

Examples:

Flags

Command flags are an array. It can contain the following simple strings (status reply):

Movablekeys

Consider SORT:

1) 1) "sort"
   2) (integer) -2
   3) 1) write
      2) denyoom
      3) movablekeys
   4) (integer) 1
   5) (integer) 1
   6) (integer) 1
   ...

Some Valkey commands have no predetermined key locations or are not easy to find. For those commands, the movablekeys flag indicates that the first key, last key, and step values are insufficient to find all the keys.

Here are several examples of commands that have the movablekeys flag:

Valkey Cluster clients need to use other measures, as follows, to locate the keys for such commands.

You can use the COMMAND GETKEYS command and have your Valkey server report all keys of a given command's invocation.

Clients can use the key specifications to identify the positions of key names. The only commands that require using COMMAND GETKEYS are SORT and MIGRATE for clients that parse keys' specifications.

For more information, please refer to the key specifications page.

First key

The position of the command's first key name argument. For most commands, the first key's position is 1. Position 0 is always the command name itself.

Last key

The position of the command's last key name argument. Valkey commands usually accept one, two or multiple number of keys.

Commands that accept a single key have both first key and last key set to 1.

Commands that accept two key name arguments, e.g. BRPOPLPUSH, SMOVE and RENAME, have this value set to the position of their second key.

Multi-key commands that accept an arbitrary number of keys, such as MSET, use the value -1.

Step

The step, or increment, between the first key and the position of the next key.

Consider the following two examples:

1) 1) "mset"
   2) (integer) -3
   3) 1) write
      2) denyoom
   4) (integer) 1
   5) (integer) -1
   6) (integer) 2
   ...
1) 1) "mget"
   2) (integer) -2
   3) 1) readonly
      2) fast
   4) (integer) 1
   5) (integer) -1
   6) (integer) 1
   ...

The step count allows us to find keys' positions. For example MSET: Its syntax is MSET _key1_ _val1_ [key2] [val2] [key3] [val3]..., so the keys are at every other position (step value of 2). Unlike MGET, which uses a step value of 1.

ACL categories

This is an array of simple strings that are the ACL categories to which the command belongs. Please refer to the Access Control List page for more information.

Command tips

Helpful information about the command. To be used by clients/proxies.

Please check the Command tips page for more information.

Key specifications

This is an array consisting of the command's key specifications. Each element in the array is a map describing a method for locating keys in the command's arguments.

For more information please check the key specifications page.

Subcommands

This is an array containing all of the command's subcommands, if any. Some Valkey commands have subcommands (e.g., the REWRITE subcommand of CONFIG). Each element in the array represents one subcommand and follows the same specifications as those of COMMAND's reply.

Examples

The following is COMMAND's output for the GET command:

1)  1) "get"
    2) (integer) 2
    3) 1) readonly
       2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
       2) @string
       3) @fast
    8) (empty array)
    9) 1) 1) "flags"
          2) 1) read
          3) "begin_search"
          4) 1) "type"
             2) "index"
             3) "spec"
             4) 1) "index"
                2) (integer) 1
          5) "find_keys"
          6) 1) "type"
             2) "range"
             3) "spec"
             4) 1) "lastkey"
                2) (integer) 0
                3) "keystep"
                4) (integer) 1
                5) "limit"
                6) (integer) 0
   10) (empty array)
...

commandlog-get

The COMMANDLOG GET command returns entries from the command log of specified type in chronological order.

The Command Log system is used to record commands that consume significant resources during server operation, including CPU, memory, and network bandwidth. These commands and the data they access may lead to abnormal instance operations, the command log can help users quickly and intuitively locate issues.

Currently, three types of command logs are supported:

Each log type has two key parameters:

  1. A threshold value that determines when a command is logged. This threshold is specific to the type of log (e.g., execution time, request size, or reply size). A negative value disables logging. A value of 0 logs all commands.
  2. A maximum length that specifies the number of entries to retain in the log. Increasing the length allows more entries to be stored but consumes additional memory. To clear all entries for a specific log type and reclaim memory, use the COMMANDLOG RESET subcommand followed by the log type.

See the details of configurations in valkey.conf.

Each entry from the specific type of command log is comprised of the following six values:

  1. A unique progressive identifier for every entry.
  2. The unix timestamp at which the logged command was processed.
  3. Each type of command log has its own meaning, currently there are three types:
    • time in microseconds for type of slow
    • size in bytes for type of large-request
    • size in bytes for type of large-reply
  4. The array composing the arguments of the command.
  5. Client peer information (e.g. Client IP address and port for TCP connected clients or unix path for unix sockets).
  6. Client name if set via the CLIENT SETNAME command.

The entry's unique ID can be used in order to avoid processing command log entries multiple times (for instance you may have a script sending you an email alert for every new command log entry). The ID is never reset in the course of the Valkey server execution, even after COMMANDLOG RESET was executed. In order to reset the ID a server restart is needed.

commandlog-help

The COMMANDLOG HELP command returns a helpful text describing the different subcommands.

commandlog-len

The COMMANDLOG LEN command returns the current number of entries in the specified type of command log.

A new entry is added to the specified command log whenever a command exceeds the corresponding threshold. There are currently three different types of command log, each with an independent threshold, including commandlog-execution-slower-than, commandlog-request-larger-than, and commandlog-reply-larger-than.

The maximum number of entries in the different command log is governed by the commandlog-slow-execution-max-len, commandlog-large-request-max-len and commandlog-large-reply-max-len configurations.

Once the command log reaches its maximal size, the oldest entry is removed whenever a new entry is created.

The command log can be cleared with the COMMANDLOG RESET command.

commandlog-reset

This command resets the specified type of command log, clearing all entries in it.

Once deleted the information is lost forever.

commandlog

This is a container command for command log management commands.

To see the list of available commands you can call COMMANDLOG HELP.

config-get

The CONFIG GET command is used to read the configuration parameters of a running Valkey server.

The symmetric command used to alter the configuration at run time is CONFIG SET.

CONFIG GET takes multiple arguments, which are glob-style patterns. Any configuration parameter matching any of the patterns are reported as a list of key-value pairs. In Valkey 9.0 and later, the list is sorted alphabetically by keys. Example:

127.0.0.1:6379> config get *max-*-entries* maxmemory
 1) "hash-max-listpack-entries"
 2) "512"
 3) "hash-max-ziplist-entries"
 4) "512"
 5) "maxmemory"
 6) "0"
 7) "set-max-intset-entries"
 8) "512"
 9) "set-max-listpack-entries"
10) "128"
11) "zset-max-listpack-entries"
12) "128"
13) "zset-max-ziplist-entries"
14) "128"

You can obtain a list of all the supported configuration parameters by typing CONFIG GET * in an open valkey-cli prompt.

All the supported parameters have the same meaning of the equivalent configuration parameter used in the valkey.conf file:

Note that you should look at the valkey.conf file relevant to the version you're working with as configuration options might change between versions. The link above is to the latest development version.

config-help

The CONFIG HELP command returns a helpful text describing the different subcommands.

config-resetstat

Resets the statistics reported by Valkey using the INFO and LATENCY HISTOGRAM commands.

The following is a non-exhaustive list of values that are reset:

config-rewrite

The CONFIG REWRITE command rewrites the valkey.conf file the server was started with, applying the minimal changes needed to make it reflect the configuration currently used by the server, which may be different compared to the original one because of the use of the CONFIG SET command.

The rewrite is performed in a very conservative way:

CONFIG REWRITE is also able to rewrite the configuration file from scratch if the original one no longer exists for some reason. However if the server was started without a configuration file at all, the CONFIG REWRITE will just return an error.

Atomic rewrite process

In order to make sure the valkey.conf file is always consistent, that is, on errors or crashes you always end with the old file, or the new one, the rewrite is performed with a single write(2) call that has enough content to be at least as big as the old file. Sometimes additional padding in the form of comments is added in order to make sure the resulting file is big enough, and later the file gets truncated to remove the padding at the end.

config-set

The CONFIG SET command is used in order to reconfigure the server at run time without the need to restart Valkey. You can change both trivial parameters or switch from one to another persistence option using this command.

The list of configuration parameters supported by CONFIG SET can be obtained issuing a CONFIG GET * command, that is the symmetrical command used to obtain information about the configuration of a running Valkey instance.

All the configuration parameters set using CONFIG SET are immediately loaded by Valkey and will take effect starting with the next command executed.

All the supported parameters have the same meaning of the equivalent configuration parameter used in the valkey.conf file.

Note that you should look at the valkey.conf file relevant to the version you're working with as configuration options might change between versions. The link above is to the latest development version.

It is possible to switch persistence from RDB snapshotting to append-only file (and the other way around) using the CONFIG SET command. For more information about how to do that please check the persistence page.

In general what you should know is that setting the appendonly parameter to yes will start a background process to save the initial append-only file (obtained from the in memory data set), and will append all the subsequent commands on the append-only file, thus obtaining exactly the same effect of a Valkey server that started with AOF turned on since the start.

You can have both the AOF enabled with RDB snapshotting if you want, the two options are not mutually exclusive.

config

This is a container command for runtime configuration commands.

To see the list of available commands you can call CONFIG HELP.

copy

This command copies the value stored at the source key to the destination key.

By default, the destination key is created in the logical database used by the connection. The DB option allows specifying an alternative logical database index for the destination key. The REPLACE option removes the destination key before copying the value to it.

The command returns zero when the source key does not exist or when the destination key already exists and the REPLACE option is not specified.

When the DB option is used, the caller must have ACL permission to access the specified destination database. See database permissions.

Examples

SET dolly "sheep"
COPY dolly clone
GET clone

dbsize

Return the number of keys in the currently-selected database.

debug

The DEBUG command is an internal command. It is meant to be used for developing and testing Valkey.

decr

Decrements the number stored at key by one. If the key does not exist, it is set to 0 before performing the operation. An error is returned if the key contains a value of the wrong type or contains a string that can not be represented as integer. This operation is limited to 64 bit signed integers.

See INCR for extra information on increment/decrement operations.

Examples

127.0.0.1:6379> SET mykey "10"
OK
127.0.0.1:6379> DECR mykey
(integer) 9
127.0.0.1:6379> SET mykey "234293482390480948029348230948"
OK
127.0.0.1:6379> DECR mykey
(error) ERR value is not an integer or out of range

decrby

Decrements the number stored at key by decrement. If the key does not exist, it is set to 0 before performing the operation. An error is returned if the key contains a value of the wrong type or contains a string that can not be represented as integer. This operation is limited to 64 bit signed integers.

See INCR for extra information on increment/decrement operations.

Examples

127.0.0.1:6379> SET mykey "10"
OK
127.0.0.1:6379> DECRBY mykey 3
(integer) 7

del

Removes the specified keys. A key is ignored if it does not exist.

Examples

127.0.0.1:6379> SET key1 "Hello"
OK
127.0.0.1:6379> SET key2 "World"
OK
127.0.0.1:6379> DEL key1 key2 key3
(integer) 2

delex

Delete key based on condition.

Options

Example

Delete the key if given value is equal to existing value.

127.0.0.1:6379> SET x 1
OK
127.0.0.1:6379> DELEX x IFEQ 1
(integer) 1

Delete the key if given value is not equal to existing value.

127.0.0.1:6379> SET x 1
OK
127.0.0.1:6379> DELEX x IFNE 2
(integer) 1

delifeq

Deletes the key if its value matches the given string.

This command is typically used to safely release locks in distributed systems, ensuring that only the owner of the lock (as identified by the value) can delete it.

If the key exists and the stored value is a string that exactly matches the provided value, the key is removed and 1 is returned. Otherwise, the key is left unchanged and 0 is returned.

Examples

Basic usage:

127.0.0.1:6379> SET mykey abc123
OK
127.0.0.1:6379> DELIFEQ mykey abc123
(integer) 1
127.0.0.1:6379> DELIFEQ mykey abc123
(integer) 0

Wrong value:

127.0.0.1:6379> SET mykey xyz789
OK
127.0.0.1:6379> DELIFEQ mykey abc123
(integer) 0

Wrong type:

127.0.0.1:6379> SADD mykey somevalue
(integer) 1
127.0.0.1:6379> DELIFEQ mykey somevalue
(error) WRONGTYPE Operation against a key holding the wrong kind of value

Use case: Safe lock release

DELIFEQ enables an atomic check-and-delete operation to safely release a lock only if the process still holds it. This avoids race conditions where a lock might expire and be claimed by another process before the original owner tries to delete it.

This pattern is commonly used as part of distributed locking systems like Redlock, which previously relied on Lua scripting to implement this logic. With DELIFEQ, such a use case becomes more robust and idiomatic.

Instead of:

EVAL "if redis.call('GET',KEYS[1]) == ARGV[1] then return redis.call('DEL',KEYS[1]) else return 0 end" 1 mykey abc123

You can now use:

DELIFEQ mykey abc123

See also

discard

Flushes all previously queued commands in a transaction and restores the connection state to normal.

If WATCH was used, DISCARD unwatches all keys watched by the connection.

dump

Serialize the value stored at key in a Valkey-specific format and return it to the user. The returned value can be synthesized back into a Valkey key using the RESTORE command.

The serialization format is opaque and non-standard, however it has a few semantic characteristics:

The serialized value does NOT contain expire information. In order to capture the time to live of the current value the PTTL command should be used.

If key does not exist a nil bulk reply is returned.

Examples

> SET mykey 10
OK
> DUMP mykey
"\x00\xc0\n\n\x00n\x9fWE\x0e\xaec\xbb"

echo

Returns message.

Examples

127.0.0.1:6379> ECHO "Hello World!"
"Hello World!"

eval

Invoke the execution of a server-side Lua script.

The first argument is the script's source code. Scripts are written in Lua and executed by the embedded Lua 5.1 interpreter in Valkey.

The second argument is the number of input key name arguments, followed by all the keys accessed by the script. These names of input keys are available to the script as the KEYS global runtime variable Any additional input arguments should not represent names of keys.

Important: to ensure the correct execution of scripts, both in standalone and clustered deployments, all names of keys that a script accesses must be explicitly provided as input key arguments. The script should only access keys whose names are given as input arguments. Scripts should never access keys with programmatically-generated names or based on the contents of data structures stored in the database.

Note: in some cases, users will abuse Lua EVAL by embedding values in the script instead of providing them as argument, and thus generating a different script on each call to EVAL. These are added to the Lua interpreter and cached to valkey-server, consuming a large amount of memory over time. Starting from Valkey 8.0, scripts loaded with EVAL or EVAL_RO will be deleted from Valkey after a certain number (least recently used order). The number of evicted scripts can be viewed through the evicted_scripts field in the stats section of the INFO command.

Please refer to the Valkey Programmability and Introduction to Eval Scripts for more information about Lua scripts.

Examples

The following example will run a script that returns the first argument that it gets.

> EVAL "return ARGV[1]" 0 hello
"hello"

eval_ro

This is a read-only variant of the EVAL command that cannot execute commands that modify data.

For more information about when to use this command vs EVAL, please refer to Read-only scripts.

For more information about EVAL scripts please refer to Introduction to Eval Scripts.

Examples

> SET mykey "Hello"
OK

> EVAL_RO "return server.call('GET', KEYS[1])" 1 mykey
"Hello"

> EVAL_RO "return server.call('DEL', KEYS[1])" 1 mykey
(error) ERR Error running script (call to b0d697da25b13e49157b2c214a4033546aba2104): @user_script:1: @user_script: 1: Write commands are not allowed from read-only scripts.

evalsha

Evaluate a script from the server's cache by its SHA1 digest.

The server caches scripts by using the SCRIPT LOAD command. The command is otherwise identical to EVAL.

Please refer to the Valkey Programmability and Introduction to Eval Scripts for more information about Lua scripts.

evalsha_ro

This is a read-only variant of the EVALSHA command that cannot execute commands that modify data.

For more information about when to use this command vs EVALSHA, please refer to Read-only scripts.

For more information about EVALSHA scripts, please refer to Introduction to Eval Scripts.

exec

Executes all previously queued commands in a transaction and restores the connection state to normal.

When using WATCH, EXEC will execute commands only if the watched keys were not modified, allowing for a check-and-set mechanism.

exists

Returns if key exists.

The user should be aware that if the same existing key is mentioned in the arguments multiple times, it will be counted multiple times. So if somekey exists, EXISTS somekey somekey will return 2.

Examples

127.0.0.1:6379> SET key1 "Hello"
OK
127.0.0.1:6379> EXISTS key1
(integer) 1
127.0.0.1:6379> EXISTS nosuchkey
(integer) 0
127.0.0.1:6379> SET key2 "World"
OK
127.0.0.1:6379> EXISTS key1 key2 nosuchkey
(integer) 2

expire

Set a timeout on key. After the timeout has expired, the key will automatically be deleted. A key with an associated timeout is often said to be volatile in Valkey terminology.

The timeout will only be cleared by commands that delete or overwrite the contents of the key, including DEL, SET, GETSET and all the *STORE commands. This means that all the operations that conceptually alter the value stored at the key without replacing it with a new one will leave the timeout untouched. For instance, incrementing the value of a key with INCR, pushing a new value into a list with LPUSH, or altering the field value of a hash with HSET are all operations that will leave the timeout untouched.

The timeout can also be cleared, turning the key back into a persistent key, using the PERSIST command.

If a key is renamed with RENAME, the associated time to live is transferred to the new key name.

If a key is overwritten by RENAME, like in the case of an existing key Key_A that is overwritten by a call like RENAME Key_B Key_A, it does not matter if the original Key_A had a timeout associated or not, the new key Key_A will inherit all the characteristics of Key_B.

Note that calling EXPIRE/PEXPIRE with a non-positive timeout or EXPIREAT/PEXPIREAT with a time in the past will result in the key being deleted rather than expired (accordingly, the emitted key event will be del, not expired).

Options

The EXPIRE command supports a set of options:

A non-volatile key is treated as an infinite TTL for the purpose of GT and LT. The GT, LT and NX options are mutually exclusive.

Refreshing expires

It is possible to call EXPIRE using as argument a key that already has an existing expire set. In this case the time to live of a key is updated to the new value. There are many useful applications for this, an example is documented in the Navigation session pattern section below.

EXPIRE would return 0 and not alter the timeout for a key with a timeout set.

Examples

127.0.0.1:6379> SET mykey "Hello"
OK
127.0.0.1:6379> EXPIRE mykey 10
(integer) 1
127.0.0.1:6379> TTL mykey
(integer) 10
127.0.0.1:6379> SET mykey "Hello World"
OK
127.0.0.1:6379> TTL mykey
(integer) -1
127.0.0.1:6379> EXPIRE mykey 10 XX
(integer) 0
127.0.0.1:6379> TTL mykey
(integer) -1
127.0.0.1:6379> EXPIRE mykey 10 NX
(integer) 1
127.0.0.1:6379> TTL mykey
(integer) 10

Pattern: Navigation session

Imagine you have a web service and you are interested in the latest N pages recently visited by your users, such that each adjacent page view was not performed more than 60 seconds after the previous. Conceptually you may consider this set of page views as a Navigation session of your user, that may contain interesting information about what kind of products he or she is looking for currently, so that you can recommend related products.

You can easily model this pattern in Valkey using the following strategy: every time the user does a page view you call the following commands:

MULTI
RPUSH pagewviews.user:<userid> http://.....
EXPIRE pagewviews.user:<userid> 60
EXEC

If the user will be idle more than 60 seconds, the key will be deleted and only subsequent page views that have less than 60 seconds of difference will be recorded.

This pattern is easily modified to use counters using INCR instead of lists using RPUSH.

Appendix: Valkey expires

Keys with an expire

Normally Valkey keys are created without an associated time to live. The key will simply live forever, unless it is removed by the user in an explicit way, for instance using the DEL command.

The EXPIRE family of commands is able to associate an expire to a given key, at the cost of some additional memory used by the key. When a key has an expire set, Valkey will make sure to remove the key when the specified amount of time elapsed.

The key time to live can be updated or entirely removed using the EXPIRE and PERSIST command (or other strictly related commands).

Expire accuracy

The expire error is from 0 to 1 milliseconds.

Expires and persistence

Keys expiring information is stored in milliseconds. This means that the time is flowing even when the Valkey instance is not active.

For expires to work well, the computer time must be taken stable. If you move an RDB file from two computers with a big desync in their clocks, funny things may happen (like all the keys loaded to be expired at loading time).

Even running instances will always check the computer clock, so for instance if you set a key with a time to live of 1000 seconds, and then set your computer time 2000 seconds in the future, the key will be expired immediately, instead of lasting for 1000 seconds.

How Valkey reclaims expired keys

Valkey reclaims expired keys in two ways: on access and in the background in what is called the "active expire key" cycles. On access expiration is when a client tries to access a key with the expiration time which is found to be timed out. Such a key is deleted on this access attempt.

Relying solely on the on access expiration only is not enough because there are expired keys that may never be accessed again. To address this, Valkey uses the background expiration algorithm known as the "active expire key" effort. This algorithm is adaptive: it tries to use less CPU if there are few expired keys to reclaim. Otherwise, it gets more aggressive trying to free more memory by reclaiming more keys in shorter runs but using more CPU.

This is how it works:

Valkey slowly scans the keyspace to identify and reclaim expired keys. This "slow cycle" is the main way to collect expired keys and operates with the server's hertz frequency (usually 10 hertz). During the slow cycle, Valkey tolerates having not more than 10% of the expired keys in the memory and tries to use a maximum of 25% CPU power. These default values are adjusted if the user changes the active expire key effort configuration.

If the number of expired keys remains high after the slow cycle, the active expire key effort transitions into the "fast cycle", trying to do less work but more often. The fast cycle runs no longer than 1000 microseconds and repeats at the same interval. During the fast cycle, the check of every database is interrupted once the number of already expired keys in the database is estimated to be lower than 10%. This is done to avoid doing too much work to gain too little memory.

You can modify the active expire key effort with the active-expire-effort parameter in the configuration file up to the maximum value of 10. The default active-expire-effort value is 1, and it is described by the following base values:

Changing the active-expire-effort value results in a lower percentage of expired keys tolerated in memory. However, it will lead to longer cycles and increased CPU usage, which may introduce latency.

To calculate the new values, use the following formulas:

where ACTIVE_EXPIRE_CYCLE_KEYS_PER_LOOP, ACTIVE_EXPIRE_CYCLE_FAST_DURATION, ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC, and ACTIVE_EXPIRE_CYCLE_ACCEPTABLE_STALE are the base values, and effort is the specified active-expire-effort.

How expires are handled in the replication link and AOF file

In order to obtain a correct behavior without sacrificing consistency, when a key expires, a DEL operation is synthesized in both the AOF file and gains all the attached replicas nodes. This way the expiration process is centralized in the primary instance, and there is no chance of consistency errors.

However while the replicas connected to a primary will not expire keys independently (but will wait for the DEL coming from the primary), they'll still take the full state of the expires existing in the dataset, so when a replica is elected to primary it will be able to expire the keys independently, fully acting as a primary.

expireat

EXPIREAT has the same effect and semantic as EXPIRE, but instead of specifying the number of seconds representing the TTL (time to live), it takes an absolute Unix timestamp (seconds since January 1, 1970). A timestamp in the past will delete the key immediately.

Please for the specific semantics of the command refer to the documentation of EXPIRE.

Background

EXPIREAT was introduced in order to convert relative timeouts to absolute timeouts for the AOF persistence mode. Of course, it can be used directly to specify that a given key should expire at a given time in the future.

Options

The EXPIREAT command supports a set of options:

A non-volatile key is treated as an infinite TTL for the purpose of GT and LT. The GT, LT and NX options are mutually exclusive.

Examples

127.0.0.1:6379> SET mykey "Hello"
OK
127.0.0.1:6379> EXISTS mykey
(integer) 1
127.0.0.1:6379> EXPIREAT mykey 1293840000
(integer) 1
127.0.0.1:6379> EXISTS mykey
(integer) 0

expiretime

Returns the absolute Unix timestamp (since January 1, 1970) in seconds at which the given key will expire.

See also the PEXPIRETIME command which returns the same information with milliseconds resolution.

Examples

127.0.0.1:6379> SET mykey "Hello"
OK
127.0.0.1:6379> EXPIREAT mykey 33177117420
(integer) 1
127.0.0.1:6379> EXPIRETIME mykey
(integer) 33177117420

failover

This command will start a coordinated failover between the currently-connected-to primary and one of its replicas. The failover is not synchronous, instead a background task will handle coordinating the failover. It is designed to limit data loss and unavailability of the cluster during the failover. This command is analogous to the CLUSTER FAILOVER command for non-clustered Valkey and is similar to the failover support provided by sentinel.

The specific details of the default failover flow are as follows:

  1. The primary will internally start a CLIENT PAUSE WRITE, which will pause incoming writes and prevent the accumulation of new data in the replication stream.
  2. The primary will monitor its replicas, waiting for a replica to indicate that it has fully consumed the replication stream. If the primary has multiple replicas, it will only wait for the first replica to catch up.
  3. The primary will then demote itself to a replica. This is done to prevent any dual primary scenarios. NOTE: The primary will not discard its data, so it will be able to rollback if the replica rejects the failover request in the next step.
  4. The previous primary will send a special PSYNC request to the target replica, PSYNC FAILOVER, instructing the target replica to become a primary.
  5. Once the previous primary receives acknowledgement the PSYNC FAILOVER was accepted it will unpause its clients. If the PSYNC request is rejected, the primary will abort the failover and return to normal.

The field master_failover_state in INFO replication can be used to track the current state of the failover, which has the following values:

NOTE: During the failover-in-progress phase, the primary first demotes itself to a replica and then notifies the replica to promote itself to primary. These two steps are an asynchronous process, which may result in the simultaneous existence of two nodes as replicas. In this scenario, for clients that support REDIRECT (explicitly execute CLIENT CAPA REDIRECT), the redirection result may bounce back and forth between the two replicas until the target replica completes the process of promoting itself to primary. To avoid this situation, during the failover-in-progress phase, we temporarily suspend the clients that need to be redirected until the replica truly becomes the primary, and then resume the execution.

If the previous primary had additional replicas attached to it, they will continue replicating from it as chained replicas. You will need to manually execute a REPLICAOF on these replicas to start replicating directly from the new primary.

Optional arguments

The following optional arguments exist to modify the behavior of the failover flow:

NOTE: The primary will always rollback if the PSYNC FAILOVER request is rejected by the target replica.

Failover abort

The failover command is intended to be safe from data loss and corruption, but can encounter some scenarios it can not automatically remediate from and may get stuck. For this purpose, the FAILOVER ABORT command exists, which will abort an ongoing failover and return the primary to its normal state. The command has no side effects if issued in the waiting-for-sync state but can introduce multi-primary scenarios in the failover-in-progress state. If a multi-primary scenario is encountered, you will need to manually identify which primary has the latest data and designate it as the primary and have the other replicas.

NOTE: REPLICAOF is disabled while a failover is in progress, this is to prevent unintended interactions with the failover that might cause data loss.

fcall

Invoke a function.

Functions are loaded to the server with the FUNCTION LOAD command. The first argument is the name of a loaded function.

The second argument is the number of input key name arguments, followed by all the keys accessed by the function. In Lua, these names of input keys are available to the function as a table that is the callback's first argument.

Important: To ensure the correct execution of functions, both in standalone and clustered deployments, all names of keys that a function accesses must be explicitly provided as input key arguments. The function should only access keys whose names are given as input arguments. Functions should never access keys with programmatically-generated names or based on the contents of data structures stored in the database.

Any additional input argument should not represent names of keys. These are regular arguments and are passed in a Lua table as the callback's second argument.

For more information please refer to the Valkey Programmability and Introduction to Valkey Functions pages.

Examples

The following example will create a library named mylib with a single function, myfunc, that returns the first argument it gets.

127.0.0.1:6379> FUNCTION LOAD "#!lua name=mylib \n server.register_function('myfunc', function(keys, args) return args[1] end)"
"mylib"
127.0.0.1:6379> FCALL myfunc 0 hello
"hello"

fcall_ro

This is a read-only variant of the FCALL command that cannot execute commands that modify data.

For more information about when to use this command vs FCALL, please refer to Read-only scripts.

For more information please refer to Introduction to Valkey Functions.

flushall

Delete all the keys of all the existing databases, not just the currently selected one. This command never fails.

By default, FLUSHALL will synchronously flush all the databases. Setting the lazyfree-lazy-user-flush configuration directive to "yes" changes the default flush mode to asynchronous.

It is possible to use one of the following modifiers to dictate the flushing mode explicitly:

Note: an asynchronous FLUSHALL command only deletes keys that were present at the time the command was invoked. Keys created during an asynchronous flush will be unaffected.

Because FLUSHALL operates on every database, the caller must have ACL access to all databases (the alldbs rule). See database permissions.

flushdb

Delete all the keys of the currently selected DB. This command never fails.

By default, FLUSHDB will synchronously flush all keys from the database. Setting the lazyfree-lazy-user-flush configuration directive to "yes" changes the default flush mode to asynchronous.

It is possible to use one of the following modifiers to dictate the flushing mode explicitly:

Note: an asynchronous FLUSHDB command only deletes keys that were present at the time the command was invoked. Keys created during an asynchronous flush will be unaffected.

ft._list

Lists the currently defined indexes for the current data base.

FT._LIST

Response

An array of strings. Each string is the name of an index in the current database. The index names are in no particular order.

Example

ft._list
1) index
2) products
3) users
4) transactions

ft.aggregate

The FT.AGGREGATE command extends the query capabilities of the FT.SEARCH command with substantial server-side data processing capabilities.

The first step of the command is to use the index name and query string to locate a list of Valkey keys. This process is identical to the FT.SEARCH command.

The second step is executed once for each key found in the first step. The contents of the key are extracted as directed by the LOAD clause, resulting in a set of name/value pairs which are collected into a record. Thus the output of this step is the working set of records, one record for each key found in the first step. If the query is a KNN query then the initial working set will be sorted by distance, otherwise the working set will be in no particular order.

The next steps are to execute the list of stages provided on the command, sequentially one at a time. Each step takes as input the working set of records and performs some transformation on it, i.e., the output of one stage is fed into the input of the next stage.

Once all stages have been executed, the working set of records output from the last stage is returned as the result of the command.

FT.AGGREGATE <index-name> <query>
    [DIALECT <dialect>]
    [INORDER]
    [LOAD * | LOAD <count> <field> [AS <alias>] [<field> [AS <alias>] ...]]
    [PARAMS <count> <name> <value> [ <name> <value> ...]]
    [SLOP <slop>]
    [TIMEOUT <timeout>]
    [VERBATIM]
    [WITHCURSOR [COUNT <count>] [MAXIDLE <maxidle>]]
    (
      | APPLY <expression> AS <field>
      | FILTER <expression>
      | GROUPBY <count> <field> [<field> ... ] [[REDUCE <reducer> <count> [<expression> [<expression> ...]]] [ REDUCE ...]]
      | LIMIT <offset> <count>
      | SORTBY <count> <expression> [ASC | DESC] [<expression [ASC | DESC] ...] [MAX <num>]
    )+

Result

The output is an array. The first element of this array is a scalar number with no particular meaning and should be ignored. The remainder of the array is one element for each record output by the final processing stage.

Each record is represented by an array which contains the field/value pairs of each record.

If WITHCURSOR is specified the output is a two element array. The first element is an array whose first element is the number of records returned, followed by one element for each returned record. The second element is the cursor id to pass to FT.CURSOR READ, or 0 if all records were returned, in which case no cursor is created.

Processing Stages

APPLY Stage

The APPLY stage processes each record of the working set in sequence. For each record the expression is computed with output being set into the record with the provided field name. It is allowed to overwrite an existing field. The apply stage does not change the number of records in the working set.

FILTER Stage

The FILTER stage processes each record of the working set in sequence. For each record the expression is computed. If the expression evaluates to zero then the record is discarded else the record remains.

LIMIT Stage

The LIMIT stage discards records from the working set based on the provided offset and count.

SORTBY Stage

The SORTBY stage reorders the records in accordance with a sort key. A sort key can be constructed using a number of expressions optionally combined with a direction.

If the MAX clause is present, then the output is trimmed after the first N records. It is more efficient to use the MAX clause than to follow the SORTBY stage with a limit stage.

GROUPBY Stage

The GROUPBY stage organizes the input records into buckets based on the values of the specified fields. For each unique combination of values a separate bucket is created to hold all records that have that combination of values.

Each bucket of records is processed into a single output record, discarding the bucket contents. That output record has two sections. The first section has one value for each of the specified GROUPBY fields. This section provides the values that formed (named) this unique bucket.

The second section is the output of the reducers for that bucket. Reducers provide an efficient mechanism for reducing (summarizing) the contents of a bucket. Each reducer function processes each record of the bucket and generates a single output value which is inserted into the second section of GROUPBY output record for this bucket.

The output of the GROUPBYstage is one record for each unique bucket.

Reducers

The following reducer functions are available. The reducer functions that take an input expression will convert that expression into a number.

Syntax Function
COUNT 0 Number of records
COUNT_DISTINCT 1 The exact number of distinct values of the expression. Caution this consumes memory proportional to the number of distinct values.
SUM 1 The numerical sum of the values of the expression.
MIN 1 The smallest numerical values of the expression.
MAX 1 The largest numerical values of the expression.
AVG 1 The numerical average of the values of the expression.
STDDEV 1 The standard deviation the values of the expression.
FIRST_VALUE 1 The first value of the expression encountered in the group. Order depends on record retrieval order. Use only when order does not matter.
FIRST_VALUE 3 BY The value of the first expression from the record with the smallest comparison expression (ascending). Ties broken by first-encountered order.
FIRST_VALUE 4 BY ASC|DESC The value of the first expression from the record with the minimum (ASC) or maximum (DESC) comparison expression. Ties broken by first-encountered order. Invalid keyword arguments (e.g., wrong BY token or unrecognized direction) produce a parse-time error.
RANDOM_SAMPLE 2 <sample_size> A random sample of values from the expression using reservoir sampling. Returns an array of up to sample_size elements (maximum 1000). Nil values are excluded. Output is non-deterministic.

ft.create

The FT.CREATE command creates an empty index and may initiate the backfill process. Each index consists of a number of field definitions. Each field definition specifies a field name, a field type and a path within each indexed key to locate a value of the declared type. Some field type definitions have additional sub-type specifiers.

For indexes on HASH keys, the default path is the same as the hash member name. The optional AS clause can be used to rename the field if desired

For indexes on JSON keys, the path is a JSON path to the data of the declared type. The AS clause is required in order to provide a field name without the special characters of a JSON path.

FT.CREATE <index-name>
    [ON HASH | ON JSON]
    [PREFIX <count> <prefix> [<prefix>...]]
    [FILTER <expression>]
    [SCORE default_value]
    [SCORE_FIELD <field_name>]
    [LANGUAGE <language>]
    [SKIPINITIALSCAN]
    [MINSTEMSIZE <min_stem_size>]
    [WITHOFFSETS | NOOFFSETS]
    [NOHL]
    [NOSTOPWORDS | STOPWORDS <count> <word> word ...]
    [PUNCTUATION <punctuation>]
    SCHEMA
        (
            <field-identifier> [AS <field-alias>]
                  NUMERIC
                | TAG [SEPARATOR <sep>] [CASESENSITIVE]
                | TEXT [NOSTEM] [WITHSUFFIXTRIE | NOSUFFIXTRIE] [WEIGHT <weight>]
                | VECTOR [HNSW | FLAT] <attr_count> [<attribute_name> <attribute_value>]+
            [SORTABLE [UNF]]
        )+

Field types

TAG: A tag field is a string that contains one or more tag values.

See Tag Field Format for more details and examples.

TEXT: A text field is a string that contains words

See Text Field Format for more details and examples.

NUMERIC: A numeric field contains a number.

See Numeric Field Format for details and examples.

VECTOR: A vector field contains a vector. Two vector indexing algorithms are currently supported: HNSW (Hierarchical Navigable Small World) and FLAT (brute force). Each algorithm has a set of additional attributes, some required and other optional.

See Vector Field Format for more details and examples.

The KNN search algorithm operates to locate vectors that are the nearest to the query vector, i.e., looking for the smallest distance value. The computation of the distance metrics is adjusted from their classical definitions in order to posses this property. This table shows the actual computation that Search uses when computing the distance between two vectors: $X$ and $Y$.

Classical Name Valkey Search Distance Metric Name Classical Distance Formula Definition Valkey Search Distance Formula
Inner Product IP dot(X,Y) 1 - dot(X,Y)
Euclidean L2 sqrt(sum((x[i]-y[i])^2)) sum((x[i]-y[i])^2)
Cosine COSINE dot(x,y) / (magnitude(X) * magnitude(Y)) 1 - (dot(X,Y) / (magnitude(X) * magnitude(Y)))

Field options

SORTABLE (optional): This parameter is not required. Any field may be used with SORTBY whether or not it is declared SORTABLE. It is recorded on the attribute and reported by FT.INFO, but does not otherwise affect indexing or query behavior.

Examples

HNSW example:

FT.CREATE my_index_name SCHEMA my_hash_field_key VECTOR HNSW 10 TYPE FLOAT32 DIM 20 DISTANCE_METRIC COSINE M 4 EF_CONSTRUCTION 100

Result:

OK

FLAT example:

FT.CREATE my_index_name SCHEMA my_hash_field_key VECTOR Flat TYPE FLOAT32 DIM 20 DISTANCE_METRIC COSINE INITIAL_CAP 15000

Result:

OK

HNSW example with a numeric field:

FT.CREATE my_index_name SCHEMA my_vector_field_key VECTOR HNSW 10 TYPE FLOAT32 DIM 20 DISTANCE_METRIC COSINE M 4 EF_CONSTRUCTION 100 my_numeric_field_key NUMERIC

Result:

OK

HNSW example with multiple tag and numeric fields

FT.CREATE my_index_name SCHEMA my_vector_field_key VECTOR HNSW          \
    10 TYPE FLOAT32 DIM 20 DISTANCE_METRIC COSINE M 4 EF_CONSTRUCTION   \
    100 my_tag_field_key_1 TAG SEPARATOR '@' CASESENSITIVE              \
    my_numeric_field_key_1 NUMERIC my_numeric_field_key_2 NUMERIC my_tag_field_key_2 TAG

Result:

OK

ft.cursor

Reads more rows from, or deletes, a cursor created by the WITHCURSOR option of FT.AGGREGATE, FT.HYBRID or FT.SEARCH.

FT.CURSOR READ <index-name> <cursor-id> [COUNT <count>]
FT.CURSOR DEL <index-name> <cursor-id>

A cursor holds the rows of a query result that have not yet been returned to the client, as of when the query ran: later changes to the data are not visible. A cursor belongs to the database it was created in: it can only be read or deleted by a connection whose currently selected database is that database. If SWAPDB moves the cursor's index to another database, its cursors move with it. In cluster mode a cursor exists only on the node that executed the query.

Reading or deleting a cursor requires the same key permissions as querying its index: a user who could not run the query that created the cursor cannot read or delete it either.

A cursor is destroyed when its last row has been read, when it is deleted with FT.CURSOR DEL, when it has not been read for longer than its MAXIDLE time, or when its index is removed (FT.DROPINDEX, FLUSHDB, FLUSHALL, or a replica synchronizing with its primary). Reading a cursor restarts its idle time.

RESPONSE

FT.CURSOR READ returns a two element array. The same format is used for cursors created by FT.AGGREGATE, FT.HYBRID and FT.SEARCH.

  1. An array whose first element is the number of rows returned, followed by one element for each row. A row of an FT.AGGREGATE or FT.HYBRID cursor is an array of field/value pairs. A row of an FT.SEARCH cursor is an array containing the elements for one key of a non-cursor FT.SEARCH response, i.e. the key name followed by the optional score, the optional sort key and the array of field/value pairs.
  2. The cursor id to use for the next FT.CURSOR READ, or 0 if all rows have been returned, in which case the cursor has been destroyed.

FT.CURSOR DEL returns OK. It applies the same checks as FT.CURSOR READ: <index-name> must name an existing index, which need not be the cursor's own, the cursor must belong to the currently selected database, and the user must have permission to read the cursor's index.

Errors:

Example

> FT.AGGREGATE idx @price:[-inf inf] LOAD 1 @price SORTBY 2 @price ASC WITHCURSOR COUNT 2
1) 1) (integer) 2
   2) 1) "price"
      2) "10"
   3) 1) "price"
      2) "20"
2) (integer) 8481957688249417729
> FT.CURSOR READ idx 8481957688249417729 COUNT 2
1) 1) (integer) 2
   2) 1) "price"
      2) "30"
   3) 1) "price"
      2) "40"
2) (integer) 8481957688249417729
> FT.CURSOR READ idx 8481957688249417729
1) 1) (integer) 1
   2) 1) "price"
      2) "50"
2) (integer) 0

ft.dropindex

Drop the index created earlier by FT.CREATE command. It is an error if the index doesn't exist.

FT.DROPINDEX <index-name>

RESPONSE OK or Error.

ft.hybrid

The FT.HYBRID command runs two searches over one index and combines their results into a single ranked list.

The first search is the SEARCH arm: a text, tag or numeric query, scored for relevance the way FT.SEARCH scores one. The second is the VSIM arm: a vector similarity search, scored by distance. Each arm ranks its own matches independently.

The two ranked lists are then fused into one. Fusion is what makes this a hybrid search rather than two searches: a document that both arms found is rewarded for appearing in both, and the COMBINE clause decides how the two arms' scores are weighed against each other.

The fused list is then fed through the same processing stages as FT.AGGREGATE, so the result can be projected, filtered, grouped, sorted and trimmed before it is returned.

FT.HYBRID <index-name>
    SEARCH <query> [SCORER <scorer>] [YIELD_SCORE_AS <alias>]
    VSIM <field> <vector> [KNN <count> [K <k>] [EF_RUNTIME <ef>] [SHARD_K_RATIO <ratio>]]
                          [FILTER [<count>] <expression>
                            [POLICY (ADHOC | BATCHES [BATCH_SIZE <n>])]]
                          [YIELD_SCORE_AS <alias>]
    [COMBINE
      ( RRF      <count> [CONSTANT <c>] [WINDOW <w>] [YIELD_SCORE_AS <alias>]
      | LINEAR   <count> [ALPHA <a> BETA <b>] [WINDOW <w>] [YIELD_SCORE_AS <alias>]
      | FUNCTION <count> EXPR <expression> [WINDOW <w>] [YIELD_SCORE_AS <alias>]
      )]
    [DIALECT <dialect>]
    [LOAD * | LOAD <count> <field> [AS <alias>] [<field> [AS <alias>] ...]]
    [PARAMS <count> <name> <value> [ <name> <value> ...]]
    [TIMEOUT <timeout>]
    [WITHCURSOR [COUNT <count>] [MAXIDLE <maxidle>]]
    (
      | APPLY <expression> AS <field>
      | FILTER <expression>
      | GROUPBY <count> <field> [<field> ... ] [[REDUCE <reducer> <count> [<expression> [<expression> ...]]] [ REDUCE ...]]
      | LIMIT <offset> <count>
      | SORTBY <count> <expression> [ASC | DESC] [<expression> [ASC | DESC] ...] [MAX <num>]
    )*

Result

The output is an array. The first element is a scalar that repeats the number of records returned and carries no other information — in particular it is not the total number of matches. The remainder is one element per record.

Each record is an array of field/value pairs. Without a LOAD clause every record carries __key and the fused score, under __score or under the alias given by COMBINE ... YIELD_SCORE_AS. A LOAD clause replaces those two implicit columns with the fields it names: load @__key to keep the key, and name the fused score with COMBINE ... YIELD_SCORE_AS to keep it. Per-arm scores appear under their own YIELD_SCORE_AS aliases either way.

If WITHCURSOR is specified the output is a two element array, as for FT.AGGREGATE. The first element is an array whose first element is the number of records returned, followed by one element for each returned record. The second element is the cursor id to pass to FT.CURSOR READ, or 0 if all records were returned, in which case no cursor is created. The cursor pages through the records the command would have returned without WITHCURSOR, so the default LIMIT of 10 described below still applies.

Unlike FT.AGGREGATE, which returns every record, FT.HYBRID returns at most 10 records when the command writes no LIMIT clause. An explicit LIMIT stays where it is written in the pipeline; only the default is appended, so it runs after every other stage.

Fusion methods

Fusion sees each arm's results ranked best-first, and every arm's score in the same direction: higher is better. The VSIM arm's distance is converted to a similarity before fusion, so a nearer document scores higher.

RRF

COMBINE RRF <count> [CONSTANT <c>] [WINDOW <w>] [YIELD_SCORE_AS <alias>]

Reciprocal Rank Fusion scores a document by its rank in each arm rather than by the arm's score, which makes it insensitive to the two arms producing scores on entirely different scales. A document at rank r in an arm contributes 1 / (c + r + 1), and the contributions from both arms are summed.

This is the default method: a command with no COMBINE clause fuses with RRF using these defaults.

LINEAR

COMBINE LINEAR <count> [ALPHA <a> BETA <b>] [WINDOW <w>] [YIELD_SCORE_AS <alias>]

A weighted sum of the arms' raw scores: a * search_score + b * vector_similarity. A document absent from an arm contributes nothing from it.

The two weights are optional together, not individually. Writing neither takes the defaults above, so COMBINE LINEAR 0 fuses exactly as COMBINE LINEAR 4 ALPHA 0.3 BETA 0.7 does. Writing exactly one is an error: the other is not defaulted for it, because a half-written pair is much more likely to be a typo than a request for a default.

Any finite value is accepted, including negative values and values greater than 1.

The scores are used as they stand, with no per-arm normalization. Normalizing would make a document's fused score depend on which other documents happened to come back in the same arm, so the same document against the same query would score differently as the corpus around it changed. Use ALPHA and BETA to balance the arms instead.

FUNCTION

COMBINE FUNCTION <count> EXPR <expression> [WINDOW <w>] [YIELD_SCORE_AS <alias>]

The fused score is whatever your expression computes from the arms' scores. This is a valkey-search extension.

Each arm's score is reachable from the expression three ways: by the arm's own YIELD_SCORE_AS alias, by position as @__arm0_score and @__arm1_score, and — for the standard two-arm shape — as @__search_score and @__vector_score.

An arm that did not return a given document has no score for it, and an expression that reads a missing arm score evaluates to 0 for that document as a whole — not merely for that term. @v * 0 + 100 yields 0, not 100, for a document the vector arm did not return. Guard with exists(@alias), which is 0 for a missing score and 1 otherwise, if such a document should keep a non-zero fused score.

WINDOW

WINDOW bounds how many of each arm's top results take part in fusion. It is a per-arm count, so with two arms the fused list can hold up to twice the window before the processing stages run.

WINDOW 0 means "as wide as allowed" and resolves to the ceiling set by the search.max-combine-window configuration, which defaults to 1,000,000. Values above that ceiling are rejected.

The ceiling bounds a window the command asks for, and the window FUNCTION takes when it asks for none. It does not clamp the RRF and LINEAR default of 20: lowering the configuration below 20 rejects an explicit WINDOW 20 while leaving the default untouched.

Score naming

The fused score is emitted under __score unless COMBINE ... YIELD_SCORE_AS names it otherwise.

__key is reserved and cannot be used as a score alias anywhere.

__score cannot be used by COMBINE ... YIELD_SCORE_AS when the command has no LOAD clause, because that is already the name of the default score column; give the score a different name, or add a LOAD clause. A per-arm YIELD_SCORE_AS cannot use __score at all, with or without a LOAD clause, since it would collide with the fused score's own column.

Notes

ft.info

The FT.INFO command provides information about an index. Variants of the command are available in cluster mode to aggregate index information across the cluster.

FT.INFO <index-name>
  [LOCAL | PRIMARY | CLUSTER]
  [ALLSHARDS | SOMESHARDS]
  [CONSISTENT | INCONSISTENT]

RESPONSE

Response when LOCAL is specified

The LOCAL response contains both the definition of the index as well as the status of that index on the node that executes the command.

An array of key value pairs.

The following four fields are only present when the index has at least one TEXT attribute.

The following field is always present:

NUMERIC Field Type Extension

TAG Field Type Extension

TEXT Field Type Extension

VECTOR Field Type Extension

FLAT VECTOR Field Type Extension.

HNSW VECTOR Field Type Extension.

Response when the PRIMARY option is specified.

An array of key value pairs

Totals are summed over the primaries that responded. With SOMESHARDS, a primary that does not respond is omitted, so totals may be lower than the full cluster's.

Inside MULTI/EXEC or a Lua script, no other nodes are queried and the LOCAL response is returned instead.

Response when the CLUSTER option is specified

An array of key value pairs

Totals, minimums and maximums are computed over the nodes that responded. With SOMESHARDS, a node that does not respond is omitted, so totals may be lower than the full cluster's.

Inside MULTI/EXEC or a Lua script, no other nodes are queried and the LOCAL response is returned instead.

ft.search

Performs a search of the specified index. The keys which match the query expression are returned.

FT.SEARCH <index> <query>
  [ALLSHARDS | SOMESHARDS]
  [CONSISTENT | INCONSISTENT]
  [DIALECT <dialect>]
  [INKEYS <count> <key> [<key> ...]]
  [INORDER]
  [LIMIT <offset> <num>]
  [NOCONTENT]
  [PARAMS <count> <name> <value> [ <name> <value> ...]]
  [RETURN <count> <field> [AS <name>] <field> [AS <name>]...]
  [SCORER <scorer>]
  [SLOP <slop>]
  [SORTBY <field> [ ASC | DESC]]
  [TIMEOUT <timeout>]
  [VERBATIM]
  [WITHCURSOR [COUNT <count>] [MAXIDLE <maxidle>]]
  [WITHSCORES]
  [WITHSORTKEYS]

Response

The shape and contents of the response depend on the options specified in the command. In all cases, the response is an array with the first element being a count of the number of keys which match the query. The value of this count is unaffected by the presence of the LIMIT clause.

The LIMIT clause trims the list of matched keys to generate a list of returned keys. The remainder of the response array is for the returned keys.

NOCONTENT or RETURN 0 was specified.

The remainder of the response array is one entry per returned key, consisting of the key name.

RETURN with arguments was specified.

The remainder of the response array is two entries per returned key. The first entry is the key name and the second entry is an array of name/value pairs. The array of name/value pairs is driven by the RETURN clause. Each of the named fields in the RETURN clause is returned along with the value of that field for this particular key. If the named field isn't present in this key then it won't be included. In addition, if this is a vector search, then one additional name/value pair will be included which is the computed vector distance for this returned key -- see Search - query language for details on how to control the name of that field. For a vector range query, the distance is included only if the query names it with $YIELD_DISTANCE_AS and the RETURN clause lists that name.

Neither NOCONTENT nor RETURN was specified.

If the index is on HASH keys, then the result is the same as if a RETURN clause had been present that listed all of the fields of a key.

If the index is on JSON keys, then one name/value pair is inserted with name $ and the value being the entire JSON key as a string. In addition, if this is a vector search, then one additional name/value pair will be included which is the computed vector distance for this returned key -- see Search - query language for details on how to control the name of that field. For a vector range query, the distance is included only if the query names it with $YIELD_DISTANCE_AS.

WITHCURSOR was specified.

The response is a three element array:

  1. The count of the number of keys which match the query, as above.
  2. An array with one element per returned key. Each element is an array holding the entries for that key described above, e.g. the key name and its array of name/value pairs.
  3. The cursor id to pass to FT.CURSOR READ, or 0 if all keys were returned, in which case no cursor is created.

Examples

Non-vector Queries On Hash Index

For these queries the following index and data definitions were used:

FT.CREATE index on hash SCHEMA color TAG city TAG
hset key1 color blue city London
hset key2 color black city Paris
hset key3 color green city Berlin
hset key4 color white city Tokyo
hset key5 color blend

A simple query returning all data of matched keys

FT.SEARCH index @color:{bl*}
1) (integer) 3
2) "key1"
3) 1) "city"
   2) "London"
   3) "color"
   4) "blue"
4) "key5"
5) 1) "color"
   2) "blend"
   3) "cityextra"
   4) "Unknown"
6) "key2"
7) 1) "city"
   2) "Paris"
   3) "color"
   4) "black"

The same query with the NOCONTENT clause.

FT.SEARCH index @color:{bl*} NOCONTENT
1) (integer) 3
2) "key1"
3) "key5"
4) "key2"

The same query with a RETURN clause.

FT.SEARCH index @color:{bl*} RETURN 2 color city
1) (integer) 3
2) "key1"
3) 1) "color"
   2) "blue"
   3) "city"
   4) "London"
4) "key5"
5) 1) "color"
   2) "blend"
6) "key2"
7) 1) "color"
   2) "black"
   3) "city"
   4) "Paris"

Non-vector Queries On JSON Index

Repeating the queries above, except the data is JSON

FT.CREATE index on json SCHEMA $.color as color TAG $.city as city TAG
json.set key1 . {"color":"blue","city":"London"}
json.set key2 . {"color":"black","city":"Paris"}
json.set key3 . {"color":"green","city":"Berlin"}
json.set key4 . {"color":"white","city":"Tokyo"}
json.set key5 . {"color":"blend","cityextra":"Unknown"}

A simple query returning all data of matched keys

FT.SEARCH index @color:{bl*}
1) (integer) 3
2) "key2"
3) 1) "$"
   2) "{\"color\":\"black\",\"city\":\"Paris\"}"
4) "key5"
5) 1) "$"
   2) "{\"color\":\"blend\",\"cityextra\":\"Unknown\"}"
6) "key1"
7) 1) "$"
   2) "{\"color\":\"blue\",\"city\":\"London\"}"

The same query with NOCONTENT

FT.SEARCH index @color:{bl*} NOCONTENT
1) (integer) 3
2) "key2"
3) "key5"
4) "key1"

The same query with a RETURN clause.

FT.SEARCH index @color:{bl*} RETURN 2 color city
1) (integer) 3
2) "key2"
3) 1) "color"
   2) "black"
   3) "city"
   4) "Paris"
4) "key5"
5) 1) "color"
   2) "blend"
6) "key1"
7) 1) "color"
   2) "blue"
   3) "city"
   4) "London"

Pure vector search query

For this example, assume we're building a property searching index where customers can search properties based on some features. Assume we have a list of properties with the following attributes:

At first, we create an HNSW index with the description as a vector field using the FT.CREATE command:

FT.CREATE idx SCHEMA description VECTOR HNSW 6 TYPE FLOAT32 DIM 3 DISTANCE_METRIC L2

Now we can insert a few properties (this can be done prior to index creation as well) using the HSET command:

HSET p1 description "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?"
HSET p2 description "\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00"
HSET p3 description "\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00"
HSET p4 description "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?"
HSET p5 description "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?"

Now we can perform queries using the FT.SEARCH command. The following query returns up to five of the most similar properties to the provided query vector:

FT.SEARCH idx "*=>[KNN 5 @description $query_vector]" PARAMS 2 query_vector "\xcd\xccL?\x00\x00\x00\x00\x00\x00\x00\x00" DIALECT 2

Returned result:

 1) (integer) 5
 2) p5
 3) 1) __description_score
    2) 1.6400001049
    3) description
    4) \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?
 4) p4
 5) 1) __description_score
    2) 1.6400001049
    3) description
    4) \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?
 6) p2
 7) 1) __description_score
    2) 1.6400001049
    3) description
    4) \x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00
 8) p1
 9) 1) __description_score
    2) 1.6400001049
    3) description
    4) \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?
10) p3
11) 1) __description_score
    2) 0.0399999953806
    3) description
    4) \x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00

Query On JSON Index without RETURN clause

Simple query showing the JSON output

Simple Query with RETURN Clause

Simple query showing selecting return of additional fields

Query showing NOCONTENT

Query showing SORTBY

function-delete

Delete a library and all its functions.

This command deletes the library called library-name and all functions in it. If the library doesn't exist, the server returns an error.

For more information please refer to Introduction to Valkey Functions.

Examples

127.0.0.1:6379> FUNCTION LOAD "#!lua name=mylib \n server.register_function('myfunc', function(keys, args) return 'hello' end)"
"mylib"
127.0.0.1:6379> FCALL myfunc 0
"hello"
127.0.0.1:6379> FUNCTION DELETE mylib
OK
127.0.0.1:6379> FCALL myfunc 0
(error) ERR Function not found

function-dump

Return the serialized payload of loaded libraries. You can restore the serialized payload later with the FUNCTION RESTORE command.

For more information please refer to Introduction to Valkey Functions.

Examples

The following example shows how to dump loaded libraries using FUNCTION DUMP and then it calls FUNCTION FLUSH deletes all the libraries. Then, it restores the original libraries from the serialized payload with FUNCTION RESTORE.

127.0.0.1:6379> FUNCTION LOAD "#!lua name=mylib \n server.register_function('myfunc', function(keys, args) return args[1] end)"
"mylib"
127.0.0.1:6379> FUNCTION DUMP
"\xf5\xc3@X@]\x1f#!lua name=mylib \n server.registe\rr_function('my@\x0b\x02', @\x06`\x12\nkeys, args) 6\x03turn`\x0c\a[1] end)\x0c\x00\xba\x98\xc2\xa2\x13\x0e$\a"
127.0.0.1:6379> FUNCTION FLUSH
OK
127.0.0.1:6379> FUNCTION RESTORE "\xf5\xc3@X@]\x1f#!lua name=mylib \n server.registe\rr_function('my@\x0b\x02', @\x06`\x12\nkeys, args) 6\x03turn`\x0c\a[1] end)\x0c\x00\xba\x98\xc2\xa2\x13\x0e$\a"
OK
127.0.0.1:6379> FUNCTION LIST
1) 1) "library_name"
   2) "mylib"
   3) "engine"
   4) "LUA"
   5) "functions"
   6) 1) 1) "name"
         2) "myfunc"
         3) "description"
         4) (nil)
         5) "flags"
         6) (empty array)

function-flush

Deletes all the libraries.

Unless called with the optional mode argument, the lazyfree-lazy-user-flush configuration directive sets the effective behavior. Valid modes are:

For more information please refer to Introduction to Valkey Functions.

function-help

The FUNCTION HELP command returns a helpful text describing the different subcommands.

function-kill

Kill a function that is currently executing.

The FUNCTION KILL command can be used only on functions that did not modify the dataset during their execution (since stopping a read-only function does not violate the scripting engine's guaranteed atomicity).

For more information please refer to Introduction to Valkey Functions.

function-list

Return information about the functions and libraries.

You can use the optional LIBRARYNAME argument to specify a pattern for matching library names. The optional WITHCODE modifier will cause the server to include the libraries source implementation in the reply.

The following information is provided for each of the libraries in the response:

For more information please refer to Introduction to Valkey Functions.

function-load

Load a library to Valkey.

The command receives a single mandatory parameter which is the source code that implements the library. The library payload must start with Shebang statement that provides a metadata about the library (like the engine to use and the library name). Shebang format: #!<engine name> name=<library name>. Currently engine name must be lua.

For the Lua engine, the implementation should declare one or more entry points to the library with the server.register_function() API. Once loaded, you can call the functions in the library with the FCALL (or FCALL_RO when applicable) command.

When attempting to load a library with a name that already exists, the Valkey server returns an error. The REPLACE modifier changes this behavior and overwrites the existing library with the new contents.

The command will return an error in the following circumstances:

For more information please refer to Introduction to Valkey Functions.

Examples

The following example will create a library named mylib with a single function, myfunc, that returns the first argument it gets.

127.0.0.1:6379> FUNCTION LOAD "#!lua name=mylib \n server.register_function('myfunc', function(keys, args) return args[1] end)"
mylib
127.0.0.1:6379> FCALL myfunc 0 hello
"hello"

function-restore

Restore libraries from the serialized payload.

You can use the optional policy argument to provide a policy for handling existing libraries. The following policies are allowed:

For more information please refer to Introduction to Valkey Functions.

function-stats

Return information about the function that's currently running and information about the available execution engines.

The reply is map with two keys:

  1. running_script: information about the running script. If there's no in-flight function, the server replies with a nil. Otherwise, this is a map with the following keys:
  1. engines: this is a map of maps. Each entry in the map represent a single engine. Engine map contains statistics about the engine like number of functions and number of libraries.

You can use this command to inspect the invocation of a long-running function and decide whether kill it with the FUNCTION KILL command.

For more information please refer to Introduction to Valkey Functions.

function

This is a container command for function commands.

To see the list of available commands you can call FUNCTION HELP.

geoadd

Adds the specified geospatial items (longitude, latitude, name) to the specified key. Data is stored into the key as a sorted set, in a way that makes it possible to query the items with the GEOSEARCH command.

The command takes arguments in the standard format x,y so the longitude must be specified before the latitude. There are limits to the coordinates that can be indexed: areas very near to the poles are not indexable.

The exact limits, as specified by EPSG:900913 / EPSG:3785 / OSGEO:41001 are the following:

The command will report an error when the user attempts to index coordinates outside the specified ranges.

Note: there is no GEODEL command because you can use ZREM to remove elements. The Geo index structure is just a sorted set.

GEOADD options

GEOADD also provides the following options:

Note: The XX and NX options are mutually exclusive.

How does it work?

The way the sorted set is populated is using a technique called Geohash. Latitude and Longitude bits are interleaved to form a unique 52-bit integer. We know that a sorted set double score can represent a 52-bit integer without losing precision.

This format allows for bounding box and radius querying by checking the 1+8 areas needed to cover the whole shape and discarding elements outside it. The areas are checked by calculating the range of the box covered, removing enough bits from the less significant part of the sorted set score, and computing the score range to query in the sorted set for each area.

What Earth model does it use?

The model assumes that the Earth is a sphere since it uses the Haversine formula to calculate distance. This formula is only an approximation when applied to the Earth, which is not a perfect sphere. The introduced errors are not an issue when used, for example, by social networks and similar applications requiring this type of querying. However, in the worst case, the error may be up to 0.5%, so you may want to consider other systems for error-critical applications.

Examples

127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEODIST Sicily Palermo Catania
"166274.1516"
127.0.0.1:6379> GEORADIUS Sicily 15 37 100 km
1) "Catania"
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km
1) "Palermo"
2) "Catania"

geodist

Return the distance between two members in the geospatial index represented by the sorted set.

Given a sorted set representing a geospatial index, populated using the GEOADD command, the command returns the distance between the two specified members in the specified unit.

If one or both the members are missing, the command returns NULL.

The unit must be one of the following, and defaults to meters:

The distance is computed assuming that the Earth is a perfect sphere, so errors up to 0.5% are possible in edge cases.

Examples

127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEODIST Sicily Palermo Catania
"166274.1516"
127.0.0.1:6379> GEODIST Sicily Palermo Catania km
"166.2742"
127.0.0.1:6379> GEODIST Sicily Palermo Catania mi
"103.3182"
127.0.0.1:6379> GEODIST Sicily Foo Bar
(nil)

geohash

Return valid Geohash strings representing the position of one or more elements in a sorted set value representing a geospatial index (where elements were added using GEOADD).

Normally Valkey represents positions of elements using a variation of the Geohash technique where positions are encoded using 52 bit integers. The encoding is also different compared to the standard because the initial min and max coordinates used during the encoding and decoding process are different. This command however returns a standard Geohash in the form of a string as described in the Wikipedia article and compatible with the geohash.org web site.

Geohash string properties

The command returns 11 characters Geohash strings, so no precision is lost compared to the Valkey internal 52 bit representation. The returned Geohashes have the following properties:

  1. They can be shortened removing characters from the right. It will lose precision but will still point to the same area.
  2. It is possible to use them in geohash.org URLs such as http://geohash.org/<geohash-string>. This is an example of such URL.
  3. Strings with a similar prefix are nearby, but the contrary is not true, it is possible that strings with different prefixes are nearby too.

Examples

127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEOHASH Sicily Palermo Catania
1) "sqc8b49rny0"
2) "sqdtr74hyu0"

geopos

Return the positions (longitude,latitude) of all the specified members of the geospatial index represented by the sorted set at key.

Given a sorted set representing a geospatial index, populated using the GEOADD command, it is often useful to obtain back the coordinates of specified members. When the geospatial index is populated via GEOADD the coordinates are converted into a 52 bit geohash, so the coordinates returned may not be exactly the ones used in order to add the elements, but small errors may be introduced.

The command can accept a variable number of arguments so it always returns an array of positions even when a single element is specified.

Examples

127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEOPOS Sicily Palermo Catania NonExisting
1) 1) "13.36138933897018433"
   2) "38.11555639549629859"
2) 1) "15.08726745843887329"
   2) "37.50266842333162032"
3) (nil)

georadius

Return the members of a sorted set populated with geospatial information using GEOADD, which are within the borders of the area specified with the center location and the maximum distance from the center (the radius).

This manual page also covers the GEORADIUS_RO and GEORADIUSBYMEMBER_RO variants (see the section below for more information).

The common use case for this command is to retrieve geospatial items near a specified point not farther than a given amount of meters (or other units). This allows, for example, to suggest mobile users of an application nearby places.

The radius is specified in one of the following units:

The command optionally returns additional information using the following options:

The command default is to return unsorted items. Two different sorting methods can be invoked using the following two options:

By default all the matching items are returned. It is possible to limit the results to the first N matching items by using the COUNT <count> option. When ANY is provided the command will return as soon as enough matches are found, so the results may not be the ones closest to the specified point, but on the other hand, the effort invested by the server is significantly lower. When ANY is not provided, the command will perform an effort that is proportional to the number of items matching the specified area and sort them, so to query very large areas with a very small COUNT option may be slow even if just a few results are returned.

By default the command returns the items to the client. It is possible to store the results with one of these options:

Read-only variants

Since GEORADIUS and GEORADIUSBYMEMBER have a STORE and STOREDIST option they are technically flagged as writing commands in the Valkey command table. For this reason read-only replicas will flag them, and Valkey Cluster replicas will redirect them to the primary instance even if the connection is in read-only mode (see the READONLY command of Valkey Cluster).

Two read-only variants of the commands were added. They are exactly like the original commands but refuse the STORE and STOREDIST options. The two variants are called GEORADIUS_RO and GEORADIUSBYMEMBER_RO, and can safely be used in replicas.

Alternative

GEOSEARCH and GEOSEARCHSTORE with the BYRADIUS argument.

Examples

127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km WITHDIST
1) 1) "Palermo"
   2) "190.4424"
2) 1) "Catania"
   2) "56.4413"
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km WITHCOORD
1) 1) "Palermo"
   2) 1) "13.36138933897018433"
      2) "38.11555639549629859"
2) 1) "Catania"
   2) 1) "15.08726745843887329"
      2) "37.50266842333162032"
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD
1) 1) "Palermo"
   2) "190.4424"
   3) 1) "13.36138933897018433"
      2) "38.11555639549629859"
2) 1) "Catania"
   2) "56.4413"
   3) 1) "15.08726745843887329"
      2) "37.50266842333162032"

georadius_ro

Read-only variant of the GEORADIUS command.

This command is identical to the GEORADIUS command, except that it doesn't support the optional STORE and STOREDIST parameters.

Alternative

GEOSEARCH with the BYRADIUS argument.

georadiusbymember

This command is exactly like GEORADIUS with the sole difference that instead of taking, as the center of the area to query, a longitude and latitude value, it takes the name of a member already existing inside the geospatial index represented by the sorted set.

The position of the specified member is used as the center of the query.

Please check the example below and the GEORADIUS documentation for more information about the command and its options.

Note that GEORADIUSBYMEMBER_RO was added to provide a read-only command that can be used in replicas. See the GEORADIUS page for more information.

Alternative

GEOSEARCH and GEOSEARCHSTORE with the BYRADIUS and FROMMEMBER arguments.

Examples

127.0.0.1:6379> GEOADD Sicily 13.583333 37.316667 "Agrigento"
(integer) 1
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEORADIUSBYMEMBER Sicily Agrigento 100 km
1) "Agrigento"
2) "Palermo"

georadiusbymember_ro

Read-only variant of the GEORADIUSBYMEMBER command.

This command is identical to the GEORADIUSBYMEMBER command, except that it doesn't support the optional STORE and STOREDIST parameters.

Alternative

GEOSEARCH with the BYRADIUS and FROMMEMBER arguments.

geosearch

Return the members of a sorted set populated with geospatial information using GEOADD, which are within the borders of the area specified by a given shape. This command extends the GEORADIUS command, so in addition to searching within circular areas, it supports searching within rectangular areas and polygon shaped areas.

This command should be used in place of the deprecated GEORADIUS and GEORADIUSBYMEMBER commands.

The query's shape is provided by one of these mandatory options:

For BYBOX and BYRADIUS based queries, the center point is provided by one of these mandatory options:

In case of BYPOLYGON based queries, the center point and the bounding box are computed based on the polygon vertices of the command. With this option, providing FROMMEMBER or FROMLONLAT is invalid.

The command optionally returns additional information using the following options:

Matching items are returned unsorted by default. To sort them, use one of the following two options:

All matching items are returned by default. To limit the results to the first N matching items, use the COUNT <count> option. When the ANY option is used, the command returns as soon as enough matches are found. This means that the results returned may not be the ones closest to the specified point, but the effort invested by the server to generate them is significantly less. When ANY is not provided, the command will perform an effort that is proportional to the number of items matching the specified area and sort them, so to query very large areas with a very small COUNT option may be slow even if just a few results are returned.

Examples

127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEOADD Sicily 12.758489 38.788135 "edge1"   17.241510 38.788135 "edge2" 
(integer) 2
127.0.0.1:6379> GEOSEARCH Sicily FROMLONLAT 15 37 BYRADIUS 200 km ASC
1) "Catania"
2) "Palermo"
127.0.0.1:6379> GEOSEARCH Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC WITHCOORD WITHDIST
1) 1) "Catania"
   2) "56.4413"
   3) 1) "15.08726745843887329"
      2) "37.50266842333162032"
2) 1) "Palermo"
   2) "190.4424"
   3) 1) "13.36138933897018433"
      2) "38.11555639549629859"
3) 1) "edge2"
   2) "279.7403"
   3) 1) "17.24151045083999634"
      2) "38.78813451624225195"
4) 1) "edge1"
   2) "279.7405"
   3) 1) "12.7584877610206604"
      2) "38.78813451624225195"
127.0.0.1:6379> GEOSEARCH Sicily BYPOLYGON 5 12.41098696654226 38.05033923003755 15.107936245794182 38.00616649901906 18.148439288534455 38.63804787603499 17.80831874257693 39.50316813110968 12.458468633214036 38.57719533463012
1) "Palermo"
2) "edge2"
127.0.0.1:6379> GEOSEARCH Sicily BYPOLYGON 5 12.41098696654226 38.05033923003755 15.107936245794182 38.00616649901906 18.148439288534455 38.63804787603499 17.80831874257693 39.50316813110968 12.458468633214036 38.57719533463012 ASC WITHCOORD WITHDIST
1) 1) "Palermo"
   2) "166482.0159"
   3) 1) "13.36138933897018433"
      2) "38.11555639549629859"
2) 1) "edge2"
   2) "180861.7725"
   3) 1) "17.24151045083999634"
      2) "38.78813451624225195"

geosearchstore

This command is like GEOSEARCH, but stores the result in destination key.

This command replaces the now deprecated GEORADIUS and GEORADIUSBYMEMBER.

By default, it stores the results in the destination sorted set with their geospatial information.

When using the STOREDIST option, the command stores the items in a sorted set populated with their distance from the center of the circle, box or polygon, as a floating-point number, in the same unit specified for that shape.

Examples

127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEOADD Sicily 12.758489 38.788135 "edge1"   17.241510 38.788135 "edge2" 
(integer) 2
127.0.0.1:6379> GEOSEARCHSTORE key1 Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC COUNT 3
(integer) 3
127.0.0.1:6379> GEOSEARCH key1 FROMLONLAT 15 37 BYBOX 400 400 km ASC WITHCOORD WITHDIST WITHHASH
1) 1) "Catania"
   2) "56.4413"
   3) (integer) 3479447370796909
   4) 1) "15.08726745843887329"
      2) "37.50266842333162032"
2) 1) "Palermo"
   2) "190.4424"
   3) (integer) 3479099956230698
   4) 1) "13.36138933897018433"
      2) "38.11555639549629859"
3) 1) "edge2"
   2) "279.7403"
   3) (integer) 3481342659049484
   4) 1) "17.24151045083999634"
      2) "38.78813451624225195"
127.0.0.1:6379> GEOSEARCHSTORE key2 Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC COUNT 3 STOREDIST
(integer) 3
127.0.0.1:6379> ZRANGE key2 0 -1 WITHSCORES
1) "Catania"
2) "56.4412578701582"
3) "Palermo"
4) "190.44242984775784"
5) "edge2"
6) "279.7403417843143"

get

Get the value of key. If the key does not exist the special value nil is returned. An error is returned if the value stored at key is not a string, because GET only handles string values.

Examples

127.0.0.1:6379> GET nonexisting
(nil)
127.0.0.1:6379> SET mykey "Hello"
OK
127.0.0.1:6379> GET mykey
"Hello"

getbit

Returns the bit value at offset in the string value stored at key.

When offset is beyond the string length, the string is assumed to be a contiguous space with 0 bits. When key does not exist it is assumed to be an empty string, so offset is always out of range and the value is also assumed to be a contiguous space with 0 bits.

Examples

127.0.0.1:6379> SETBIT mykey 7 1
(integer) 0
127.0.0.1:6379> GETBIT mykey 0
(integer) 0
127.0.0.1:6379> GETBIT mykey 7
(integer) 1
127.0.0.1:6379> GETBIT mykey 100
(integer) 0

getdel

Get the value of key and delete the key. This command is similar to GET, except for the fact that it also deletes the key on success (if and only if the key's value type is a string).

Examples

127.0.0.1:6379> SET mykey "Hello"
OK
127.0.0.1:6379> GETDEL mykey
"Hello"
127.0.0.1:6379> GET mykey
(nil)

getex

Get the value of key and optionally set its expiration. GETEX is similar to GET, but is a write command with additional options.

Options

The GETEX command supports a set of options that modify its behavior:

Examples

127.0.0.1:6379> SET mykey "Hello"
OK
127.0.0.1:6379> GETEX mykey
"Hello"
127.0.0.1:6379> TTL mykey
(integer) -1
127.0.0.1:6379> GETEX mykey EX 60
"Hello"
127.0.0.1:6379> TTL mykey
(integer) 60

getrange

Returns the substring of the string value stored at key, determined by the offsets start and end (both are inclusive). Negative offsets can be used in order to provide an offset starting from the end of the string. So -1 means the last character, -2 the penultimate and so forth.

The function handles out of range requests by limiting the resulting range to the actual length of the string.

Examples

127.0.0.1:6379> SET mykey "This is a string"
OK
127.0.0.1:6379> GETRANGE mykey 0 3
"This"
127.0.0.1:6379> GETRANGE mykey -3 -1
"ing"
127.0.0.1:6379> GETRANGE mykey 0 -1
"This is a string"
127.0.0.1:6379> GETRANGE mykey 10 100
"string"

getset

Atomically sets key to value and returns the old value stored at key. Returns an error when key exists but does not hold a string value. Any previous time to live associated with the key is discarded on successful SET operation.

Design pattern

GETSET can be used together with INCR for counting with atomic reset. For example: a process may call INCR against the key mycounter every time some event occurs, but from time to time we need to get the value of the counter and reset it to zero atomically. This can be done using GETSET mycounter "0":

127.0.0.1:6379> INCR mycounter
(integer) 1
127.0.0.1:6379> GETSET mycounter "0"
"1"
127.0.0.1:6379> GET mycounter
"0"

Alternative

SET with the GET argument.

Examples

127.0.0.1:6379> SET mykey "Hello"
OK
127.0.0.1:6379> GETSET mykey "World"
"Hello"
127.0.0.1:6379> GET mykey
"World"

hdel

Removes the specified fields from the hash stored at key. Specified fields that do not exist within this hash are ignored. If key does not exist, it is treated as an empty hash and this command returns 0.

Examples

127.0.0.1:6379> HSET myhash field1 "foo"
(integer) 1
127.0.0.1:6379> HDEL myhash field1
(integer) 1
127.0.0.1:6379> HDEL myhash field2
(integer) 0

hello

Switch to a different protocol, optionally authenticating and setting the connection's name, or provide a contextual client report.

Valkey supports two protocols: RESP2 and RESP3. RESP3 has certain advantages since when the connection is in this mode, Valkey is able to reply with more semantical replies: for instance, HGETALL will return a map type, so a client library implementation no longer requires to know in advance to translate the array into a hash before returning it to the caller. For a full coverage of RESP3, please check the RESP3 specification.

Valkey connections start in RESP2 mode, so clients implementing RESP2 do not need to updated or changed. There are no short term plans to drop support for RESP2, although future version may default to RESP3.

HELLO always replies with a list of current server and connection properties, such as: versions, modules loaded, client ID, replication role and so forth. The availability_zone field only shows up when it is set in the configs, see availability-zone config for more details, added in Valkey 8.1.

When called without any arguments and its default use of RESP2 protocol, the reply looks like this:

> HELLO
 1) "server"
 2) "redis"
 3) "version"
 4) "255.255.255"
 5) "proto"
 6) (integer) 2
 7) "id"
 8) (integer) 5
 9) "mode"
10) "standalone"
11) "role"
12) "master"
13) "modules"
14) (empty array)
15) "availability_zone"
16) "us-east-1"

Clients that want to handshake using the RESP3 mode need to call the HELLO command and specify the value "3" as the protover argument, like so:

> HELLO 3
1# "server" => "redis"
2# "version" => "7.2.4"
3# "proto" => (integer) 3
4# "id" => (integer) 10
5# "mode" => "standalone"
6# "role" => "master"
7# "modules" => (empty array)
8# "availability_zone" => "us-east-1"

Because HELLO replies with useful information, and given that protover is optional or can be set to "2", client library authors may consider using this command instead of the canonical PING when setting up the connection.

When called with the optional protover argument, this command switches the protocol to the specified version and also accepts the following options:

hexists

Returns if field is an existing field in the hash stored at key.

Examples

127.0.0.1:6379> HSET myhash field1 "foo"
(integer) 1
127.0.0.1:6379> HEXISTS myhash field1
(integer) 1
127.0.0.1:6379> HEXISTS myhash field2
(integer) 0

hexpire

The HEXPIRE command allows manipulating the expiration time for existing hash fields. When set, the expiration time of a hash field will determine when the field will be automatically deleted. Note, that providing a millisecond time of '0' will cause immediate expiration and deletion of the field(s).

Options

The HEXPIRE command supports a set of options that modify its behavior:

Examples

127.0.0.1:6379> HSET myhash f1 v1 f2 v2 f3 v3
(integer) 3
127.0.0.1:6379> HEXPIRE myhash 10 FIELDS 2 f2 f3
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> HTTL myhash FIELDS 3 f1 f2 f3
1) (integer) -1
2) (integer) 8
3) (integer) 8

hexpireat

HEXPIREAT has the same effect and semantic as HEXPIRE, but instead of specifying the number of seconds representing the TTL (time to live), it takes an absolute Unix timestamp (seconds since January 1, 1970). A timestamp in the past will delete the key immediately.

For the specific semantics of the command refer to the documentation of HEXPIRE.

Options

The HEXPIREAT command supports a set of options that modify its behavior:

Examples

127.0.0.1:6379> HSET myhash f1 v1 f2 v2 f3 v3
(integer) 3
27.0.0.1:6379> HEXPIREAT myhash 1754846600 FIELDS 2 f2 f3
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> HEXPIRETIME myhash FIELDS 3 f1 f2 f3
1) (integer) -1
2) (integer) 1754846600
3) (integer) 1754846600

hexpiretime

The HEXPIRETIME command returns the absolute Unix timestamp (since January 1, 1970) in seconds at which the given hash field(s) will expire or -1 if the hash field doesn't have expiration time.

See also the HPEXPIRETIME command that returns the same information with milliseconds resolution.

Examples

127.0.0.1:6379> HSET myhash f1 v1 f2 v2 f3 v3
(integer) 3
27.0.0.1:6379> HEXPIREAT myhash 1754846600 FIELDS 2 f2 f3
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> HEXPIRETIME myhash FIELDS 4 f1 f2 f3 non-exist
1) (integer) -1
2) (integer) 1754846600
3) (integer) 1754846600
4) (integer) -2

hget

Returns the value associated with field in the hash stored at key.

Examples

127.0.0.1:6379> HSET myhash field1 "foo"
(integer) 1
127.0.0.1:6379> HGET myhash field1
"foo"
127.0.0.1:6379> HGET myhash field2
(nil)

hgetall

Returns all fields and values of the hash stored at key. In the returned value, every field name is followed by its value, so the length of the reply is twice the size of the hash.

Examples

127.0.0.1:6379> HSET myhash field1 "Hello"
(integer) 1
127.0.0.1:6379> HSET myhash field2 "World"
(integer) 1
127.0.0.1:6379> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "World"

hgetdel

The HGETDEL command returns the values associated with the specified fields in the hash stored at key and deletes those fields from the hash.

For every field that does not exist in the hash, a nil value is returned. Because non-existing keys are treated as empty hashes, running HGETDEL against a non-existing key will return a list of nil values.

When the last field is deleted, the key is also deleted.

Examples

127.0.0.1:6379> HSET myhash f1 v1 f2 v2 f3 v3
(integer) 3
127.0.0.1:6379> HGETDEL myhash FIELDS 1 f2
1) "v2"
127.0.0.1:6379> HGETDEL myhash FIELDS 1 f2
1) (nil)
127.0.0.1:6379> HGETALL myhash
1) "f1"
2) "v1"
3) "f3"
4) "v3"
127.0.0.1:6379>  HGETDEL myhash FIELDS 2 f2 f3
1) (nil)
2) "v3"
127.0.0.1:6379> HGETALL myhash
1) "f1"
2) "v1"
127.0.0.1:6379> HGETDEL myhash FIELDS 3 f1 non-exist
(error) ERR syntax error
127.0.0.1:6379> HGETDEL myhash FIELDS 2 f1 non-exist
1) "v1"
2) (nil)
127.0.0.1:6379> HGETALL myhash
(empty array)

hgetex

The HGETEX command returns the value of one or more fields of a given hash key, and optionally manipulates their expiration time. The command will return an array in the size of the number of requested fields. Without providing any optional flags, this command behaves exactly like a normal HMGET command.

Options

The HGETEX command supports a set of options that modify its behavior:

Note for the following:

  1. The EX, PX, EXAT, PXAT, and PERSIST options are mutually exclusive.
  2. Providing '0' expiration TTL via EX or PX optional arguments will cause the specified fields to expire immediately and be removed from the hash.
  3. Providing past expiration time via EXAT or PXAT optional arguments will cause the specified fields to expire immediately and be removed from the hash.

Examples

127.0.0.1:6379> HSET myhash f1 v1 f2 v2 f3 v3
(integer) 3
27.0.0.1:6379> HGETEX myhash EX 10 FIELDS 2 f2 f3
1) "v2"
2) "v3"
127.0.0.1:6379> HTTL myhash FIELDS 3 f1 f2 f3
1) (integer) -1
2) (integer) 8
3) (integer) 8
127.0.0.1:6379> HGETEX myhash EX 0 FIELDS 3 f1 f2 f3 
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> HGETEX myhash FIELDS 3 f1 f2 f3 
1) (nil)
2) (nil)
3) (nil)

hincrby

Increments the number stored at field in the hash stored at key by increment. If key does not exist, a new key holding a hash is created. If field does not exist the value is set to 0 before the operation is performed.

The range of values supported by HINCRBY is limited to 64 bit signed integers.

Examples

Since the increment argument is signed, both increment and decrement operations can be performed:

127.0.0.1:6379> HSET myhash field 5
(integer) 1
127.0.0.1:6379> HINCRBY myhash field 1
(integer) 6
127.0.0.1:6379> HINCRBY myhash field -1
(integer) 5
127.0.0.1:6379> HINCRBY myhash field -10
(integer) -5

hincrbyfloat

Increment the specified field of a hash stored at key, and representing a floating point number, by the specified increment. If the increment value is negative, the result is to have the hash field value decremented instead of incremented. If the field does not exist, it is set to 0 before performing the operation. An error is returned if one of the following conditions occur:

The exact behavior of this command is identical to the one of the INCRBYFLOAT command, please refer to the documentation of INCRBYFLOAT for further information.

Examples

127.0.0.1:6379> HSET mykey field 10.50
(integer) 1
127.0.0.1:6379> HINCRBYFLOAT mykey field 0.1
"10.6"
127.0.0.1:6379> HINCRBYFLOAT mykey field -5
"5.6"
127.0.0.1:6379> HSET mykey field 5.0e3
(integer) 0
127.0.0.1:6379> HINCRBYFLOAT mykey field 2.0e2
"5200"

Implementation details

The command is always propagated in the replication link and the Append Only File as a HSET operation, so that differences in the underlying floating point math implementation will not be sources of inconsistency.

hkeys

Returns all field names in the hash stored at key.

Examples

127.0.0.1:6379> HSET myhash field1 "Hello"
(integer) 1
127.0.0.1:6379> HSET myhash field2 "World"
(integer) 1
127.0.0.1:6379> HKEYS myhash
1) "field1"
2) "field2"

hlen

Returns the number of fields contained in the hash stored at key.

Examples

127.0.0.1:6379> HSET myhash field1 "Hello"
(integer) 1
127.0.0.1:6379> HSET myhash field2 "World"
(integer) 1
127.0.0.1:6379> HLEN myhash
(integer) 2

hmget

Returns the values associated with the specified fields in the hash stored at key.

For every field that does not exist in the hash, a nil value is returned. Because non-existing keys are treated as empty hashes, running HMGET against a non-existing key will return a list of nil values.

127.0.0.1:6379> HSET myhash field1 "Hello"
(integer) 1
127.0.0.1:6379> HSET myhash field2 "World"
(integer) 1
127.0.0.1:6379> HMGET myhash field1 field2 nofield
1) "Hello"
2) "World"
3) (nil)

hmset

Sets the specified fields to their respective values in the hash stored at key. This command overwrites any specified fields already existing in the hash. If key does not exist, a new key holding a hash is created.

Alternative

HSET with multiple field-value pairs.

Examples

127.0.0.1:6379> HMSET myhash field1 "Hello" field2 "World"
OK
127.0.0.1:6379> HGET myhash field1
"Hello"
127.0.0.1:6379> HGET myhash field2
"World"

hpersist

The HPERSIST remove the existing expiration on a hash key's field(s), turning the field(s) from volatile (a field with expiration set) to persistent (a field that will never expire as no TTL (time to live) is associated).

Examples

127.0.0.1:6379> HSET myhash f1 v1 f2 v2 f3 v3
(integer) 3
27.0.0.1:6379> HEXPIRE myhash 1000 FIELDS 2 f2 f3
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> HTTL myhash FIELDS 3 f1 f2 f3
1) (integer) -1
2) (integer) 998
3) (integer) 998
127.0.0.1:6379> HPERSIST myhash FIELDS 3 f1 f2 f3
1) (integer) -1
2) (integer) 1
3) (integer) 1
127.0.0.1:6379> HTTL myhash FIELDS 3 f1 f2 f3
1) (integer) -1
2) (integer) -1
3) (integer) -1

hpexpire

This command works exactly like HEXPIRE but the time to live of the field(s) is specified in milliseconds instead of seconds. Note, that providing a millisecond time of '0' will cause immediate expiration and reclamation of the field(s).

Options

The HPEXPIRE command supports a set of options that modify its behavior:

Examples

127.0.0.1:6379> HSET myhash f1 v1 f2 v2 f3 v3
(integer) 3
127.0.0.1:6379> HPEXPIRE myhash 10000 FIELDS 2 f2 f3
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> HPTTL myhash FIELDS 3 f1 f2 f3
1) (integer) -1
2) (integer) 9597
3) (integer) 9597

hpexpireat

HEXPIREAT has the same effect and semantic as HPEXPIRE, but instead of specifying the number of milliseconds representing the TTL (time to live), it takes an absolute Unix timestamp (milliseconds since January 1, 1970). A timestamp in the past will delete the key immediately.

For the specific semantics of the command refer to the documentation of HPEXPIRE.

Options

The HPEXPIREAT command supports a set of options that modify its behavior:

Examples

127.0.0.1:6379> HSET myhash f1 v1 f2 v2 f3 v3
(integer) 3
127.0.0.1:6379> HPEXPIREAT myhash 1754847944000 FIELDS 2 f2 f3
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> HPEXPIRETIME myhash FIELDS 3 f1 f2 f3
1) (integer) -1
2) (integer) 1754847944000
3) (integer) 1754847944000

hpexpiretime

The HPEXPIRETIME command returns the absolute Unix timestamp (since January 1, 1970) in milliseconds at which the given hash field(s) will expire.

See also the HEXPIRETIME command which returns the same information with seconds resolution.

Examples

127.0.0.1:6379> HSET myhash f1 v1 f2 v2 f3 v3
(integer) 3
27.0.0.1:6379> HPEXPIREAT myhash 1754847944000 FIELDS 2 f2 f3
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> HPEXPIRETIME myhash FIELDS 4 f1 f2 f3 non-exist
1) (integer) -1
2) (integer) 1754847944000
3) (integer) 1754847944000
4) (integer) -2

hpttl

Like HTTL this command returns the remaining time to live of hash field(s) that has an associated expiration time, with the sole difference that HTTL returns the amount of remaining time in seconds while HPTTL returns it in milliseconds.

See also the HTTL command that returns the same information with seconds resolution.

Examples

127.0.0.1:6379> HSET myhash f1 v1 f2 v2 f3 v3
(integer) 3
27.0.0.1:6379> HPEXPIRE myhash 10000 FIELDS 2 f2 f3
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> HPTTL myhash FIELDS 3 f1 f2 f3
1) (integer) -1
2) (integer) 9597
3) (integer) 9597

hrandfield

When called with just the key argument, return a random field from the hash value stored at key.

If the provided count argument is positive, return an array of distinct fields. The array's length is either count or the hash's number of fields (HLEN), whichever is lower.

If called with a negative count, the behavior changes and the command is allowed to return the same field multiple times. In this case, the number of returned fields is the absolute value of the specified count.

The optional WITHVALUES modifier changes the reply so it includes the respective values of the randomly selected hash fields.

Examples

127.0.0.1:6379> HSET coin heads obverse tails reverse edge null
(integer) 3
127.0.0.1:6379> HRANDFIELD coin
"heads"
127.0.0.1:6379> HRANDFIELD coin
"heads"
127.0.0.1:6379> HRANDFIELD coin -5 WITHVALUES
 1) "heads"
 2) "obverse"
 3) "tails"
 4) "reverse"
 5) "edge"
 6) "null"
 7) "heads"
 8) "obverse"
 9) "edge"
10) "null"

Specification of the behavior when count is passed

When the count argument is a positive value this command behaves as follows:

When the count is a negative value, the behavior changes as follows:

hscan

See SCAN for HSCAN documentation.

hset

Sets the specified fields to their respective values in the hash stored at key.

This command overwrites the values of specified fields that exist in the hash. If key doesn't exist, a new key holding a hash is created.

Examples

127.0.0.1:6379> HSET myhash field1 "Hello"
(integer) 1
127.0.0.1:6379> HGET myhash field1
"Hello"
127.0.0.1:6379> HSET myhash field2 "Hi" field3 "World"
(integer) 2
127.0.0.1:6379> HGET myhash field2
"Hi"
127.0.0.1:6379> HGET myhash field3
"World"
127.0.0.1:6379> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "Hi"
5) "field3"
6) "World"

hsetex

The HSETEX command allows setting the value of one or more fields of a given hash key, and optionally manipulating their expiration time. The command will return 1 in case all provided fields have been set or 0 in case FNX or FXX were provided and none of the specified fields were set. Without providing any optional flags, this command behaves exactly like a normal HSET command.

Options

The HSETEX command supports a set of options that modify its behavior:

Note for the following:

  1. The EX, PX, EXAT, PXAT, and KEEPTTL options are mutually exclusive.
  2. Setting a value on a volatile hash field (A field which has an assigned expiration time) will remove the expiration for that field.
  3. Providing '0' expiration TTL via EX or PX optional arguments will result in the specified fields immediately expiring and being removed from the hash.
  4. Providing past expiration time via EXAT or PXAT optional arguments will result in the specified fields immediately expiring and being removed from the hash.

Examples

Add 3 new items without expiration time to a 'myhash'

127.0.0.1:6379> HSETEX myhash FIELDS 3 f1 v1 f2 v2 f3 v3
(integer) 1

Unsuccessful attempt setting expiration time on EXISTING fields

127.0.0.1:6379> HSETEX myhash FNX EX 10 FIELDS 2 f2 v2 f3 v3
(integer) 0

Successful attempt setting expiration time on EXISTING fields

127.0.0.1:6379> HSETEX myhash FXX EX 10 FIELDS 2 f2 v2 f3 v3
(integer) 1

Verify hash fields expiration time:

127.0.0.1:6379> HTTL myhash FIELDS 3 f1 f2 f3
1) (integer) -1
2) (integer) 8
3) (integer) 8

Override all hash items will also persist the fields

127.0.0.1:6379> HSETEX myhash FIELDS 3 f1 v1 f2 v2 f3 v3
(integer) 1
127.0.0.1:6379> HTTL myhash FIELDS 3 f1 f2 f3
1) (integer) -1
2) (integer) -1
3) (integer) -1

Setting expiration time in the past will remove all the elements in the hash:

127.0.0.1:6379> HSETEX EX 0 myhash FIELDS 3 f1 v1 f2 v2 f3 v3
(integer) 1
127.0.0.1:6379> HTTL myhash FIELDS 3 f1 f2 f3
1) (integer) -2
2) (integer) -2
3) (integer) -2
127.0.0.1:6379> HLEN myhash
(integer) 0
127.0.0.1:6379> EXISTS myhash
(integer) 0

hsetnx

Sets field in the hash stored at key to value, only if field does not yet exist. If key does not exist, a new key holding a hash is created. If field already exists, this operation has no effect.

Examples

127.0.0.1:6379> HSETNX myhash field "Hello"
(integer) 1
127.0.0.1:6379> HSETNX myhash field "World"
(integer) 0
127.0.0.1:6379> HGET myhash field
"Hello"

hstrlen

Returns the string length of the value associated with field in the hash stored at key. If the key or the field do not exist, 0 is returned.

Examples

127.0.0.1:6379> HSET myhash f1 HelloWorld f2 99 f3 -256
(integer) 3
127.0.0.1:6379> HSTRLEN myhash f1
(integer) 10
127.0.0.1:6379> HSTRLEN myhash f2
(integer) 2
127.0.0.1:6379> HSTRLEN myhash f3
(integer) 4

httl

The HTTL command returns the remaining time to live of hash field(s) with associated expiration time(s). This introspection capability allows a Valkey client to check how many seconds a given hash field will continue to be part of the hash object.

See also the HPTTL command that returns the same information with milliseconds resolution.

Examples

127.0.0.1:6379> HSET myhash f1 v1 f2 v2 f3 v3
(integer) 3
27.0.0.1:6379> HEXPIRE myhash 10 FIELDS 2 f2 f3
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> HTTL myhash FIELDS 4 f1 f2 f3 non-exist
1) (integer) -1
2) (integer) 8
3) (integer) 8
4) (integer) -2

hvals

Returns all values in the hash stored at key.

Examples

127.0.0.1:6379> HSET myhash field1 "Hello"
(integer) 1
127.0.0.1:6379> HSET myhash field2 "World"
(integer) 1
127.0.0.1:6379> HVALS myhash
1) "Hello"
2) "World"

incr

Increments the number stored at key by one. If the key does not exist, it is set to 0 before performing the operation. An error is returned if the key contains a value of the wrong type or contains a string that can not be represented as integer. This operation is limited to 64 bit signed integers.

Note: this is a string operation because Valkey does not have a dedicated integer type. The string stored at the key is interpreted as a base-10 64 bit signed integer to execute the operation.

Valkey stores integers in their integer representation, so for string values that actually hold an integer, there is no overhead for storing the string representation of the integer.

Examples

127.0.0.1:6379> SET mykey "10"
OK
127.0.0.1:6379> INCR mykey
(integer) 11
127.0.0.1:6379> GET mykey
"11"

Pattern: Counter

The counter pattern is the most obvious thing you can do with Valkey atomic increment operations. The idea is simply send an INCR command to Valkey every time an operation occurs. For instance in a web application we may want to know how many page views this user did every day of the year.

To do so the web application may simply increment a key every time the user performs a page view, creating the key name concatenating the User ID and a string representing the current date.

This simple pattern can be extended in many ways:

Pattern: Rate limiter

The rate limiter pattern is a special counter that is used to limit the rate at which an operation can be performed. The classical materialization of this pattern involves limiting the number of requests that can be performed against a public API.

We provide two implementations of this pattern using INCR, where we assume that the problem to solve is limiting the number of API calls to a maximum of ten requests per second per IP address.

Pattern: Rate limiter 1

The more simple and direct implementation of this pattern is the following:

FUNCTION LIMIT_API_CALL(ip)
ts = CURRENT_UNIX_TIME()
keyname = ip+":"+ts
MULTI
    INCR(keyname)
    EXPIRE(keyname,10)
EXEC
current = RESPONSE_OF_INCR_WITHIN_MULTI
IF current > 10 THEN
    ERROR "too many requests per second"
ELSE
    PERFORM_API_CALL()
END

Basically we have a counter for every IP, for every different second. But these counters are always incremented setting an expire of 10 seconds so that they'll be removed by Valkey automatically when the current second is a different one.

Note the used of MULTI and EXEC in order to make sure that we'll both increment and set the expire at every API call.

Pattern: Rate limiter 2

An alternative implementation uses a single counter, but is a bit more complex to get it right without race conditions. We'll examine different variants.

FUNCTION LIMIT_API_CALL(ip):
current = GET(ip)
IF current != NULL AND current > 10 THEN
    ERROR "too many requests per second"
ELSE
    value = INCR(ip)
    IF value == 1 THEN
        EXPIRE(ip,1)
    END
    PERFORM_API_CALL()
END

The counter is created in a way that it only will survive one second, starting from the first request performed in the current second. If there are more than 10 requests in the same second the counter will reach a value greater than 10, otherwise it will expire and start again from 0.

In the above code there is a race condition. If for some reason the client performs the INCR command but does not perform the EXPIRE the key will be leaked until we'll see the same IP address again.

This can be fixed easily turning the INCR with optional EXPIRE into a Lua script that is send using the EVAL command (only available since Valkey version 2.6).

local current
current = server.call("incr",KEYS[1])
if current == 1 then
    server.call("expire",KEYS[1],1)
end

There is a different way to fix this issue without using scripting, by using Lists instead of counters. The implementation is more complex and uses more advanced features but has the advantage of remembering the IP addresses of the clients currently performing an API call, that may be useful or not depending on the application.

FUNCTION LIMIT_API_CALL(ip)
current = LLEN(ip)
IF current > 10 THEN
    ERROR "too many requests per second"
ELSE
    IF EXISTS(ip) == FALSE
        MULTI
            RPUSH(ip,ip)
            EXPIRE(ip,1)
        EXEC
    ELSE
        RPUSHX(ip,ip)
    END
    PERFORM_API_CALL()
END

The RPUSHX command only pushes the element if the key already exists.

Note that we have a race here, but it is not a problem: EXISTS may return false but the key may be created by another client before we create it inside the MULTI / EXEC block. However this race will just miss an API call under rare conditions, so the rate limiting will still work correctly.

incrby

Increments the number stored at key by increment. If the key does not exist, it is set to 0 before performing the operation. An error is returned if the key contains a value of the wrong type or contains a string that can not be represented as integer. This operation is limited to 64 bit signed integers.

See INCR for extra information on increment/decrement operations.

Examples

127.0.0.1:6379> SET mykey "10"
OK
127.0.0.1:6379> INCRBY mykey 5
(integer) 15

incrbyfloat

Increment the string representing a floating point number stored at key by the specified increment. By using a negative increment value, the result is that the value stored at the key is decremented (by the obvious properties of addition). If the key does not exist, it is set to 0 before performing the operation. An error is returned if one of the following conditions occur:

If the command is successful the new incremented value is stored as the new value of the key (replacing the old one), and returned to the caller as a string.

Both the value already contained in the string key and the increment argument can be optionally provided in exponential notation, however the value computed after the increment is stored consistently in the same format, that is, an integer number followed (if needed) by a dot, and a variable number of digits representing the decimal part of the number. Trailing zeroes are always removed.

The precision of the output is fixed at 17 digits after the decimal point regardless of the actual internal precision of the computation.

Examples

127.0.0.1:6379> SET mykey 10.50
OK
127.0.0.1:6379> INCRBYFLOAT mykey 0.1
"10.6"
127.0.0.1:6379> INCRBYFLOAT mykey -5
"5.6"
127.0.0.1:6379> SET mykey 5.0e3
OK
127.0.0.1:6379> INCRBYFLOAT mykey 2.0e2
"5200"

Implementation details

The command is always propagated in the replication link and the Append Only File as a SET operation, so that differences in the underlying floating point math implementation will not be sources of inconsistency.

info

The INFO command returns information and statistics about the server in a format that is simple to parse by computers and easy to read by humans.

The optional parameter can be used to select a specific section of information:

It can also take the following values:

When no parameter is provided, the default option is assumed.

127.0.0.1:6379> INFO
# Server
redis_version:7.2.4
server_name:valkey
valkey_version:255.255.255
redis_git_sha1:b0d5a0f5
redis_git_dirty:1
redis_build_id:1cadaf78f6168f2d
server_mode:standalone
os:Linux 6.1.0-18-amd64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:12.2.0
process_id:982599
process_supervised:no
run_id:e0abe2248cad0c6d9cb2445d8e6b73448f567f74
tcp_port:6379
server_time_usec:1714701488527373
uptime_in_seconds:94798
uptime_in_days:1
hz:10
configured_hz:10
lru_clock:3425456
executable:/home/viktor/repos/valkey/src/./valkey-server
config_file:
io_threads_active:0
availability_zone:
listener0:name=tcp,bind=*,bind=-::*,port=6379

# Clients
connected_clients:1
cluster_connections:0
maxclients:10000
client_recent_max_input_buffer:20480
client_recent_max_output_buffer:0
blocked_clients:0
tracking_clients:0
pubsub_clients:0
watching_clients:0
clients_in_timeout_table:0
total_watched_keys:0
total_blocking_keys:0
total_blocking_keys_on_nokey:0
paused_reason:none
paused_actions:none
paused_timeout_milliseconds:0

# Memory
used_memory:4757704
used_memory_human:4.54M
used_memory_rss:13221888
used_memory_rss_human:12.61M
used_memory_peak:4777616
used_memory_peak_human:4.56M
used_memory_peak_perc:99.58%
used_memory_overhead:989344
used_memory_startup:988648
used_memory_dataset:3768360
used_memory_dataset_perc:99.98%
allocator_allocated:4789624
allocator_active:5042176
allocator_resident:9252864
allocator_muzzy:0
total_system_memory:33280372736
total_system_memory_human:30.99G
used_memory_lua:31744
used_memory_vm_eval:31744
used_memory_lua_human:31.00K
used_memory_scripts_eval:0
number_of_cached_scripts:0
number_of_functions:0
number_of_libraries:0
used_memory_vm_functions:33792
used_memory_vm_total:65536
used_memory_vm_total_human:64.00K
used_memory_functions:184
used_memory_scripts:184
used_memory_scripts_human:184B
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.05
allocator_frag_bytes:252552
allocator_rss_ratio:1.84
allocator_rss_bytes:4210688
rss_overhead_ratio:1.43
rss_overhead_bytes:3969024
mem_fragmentation_ratio:2.80
mem_fragmentation_bytes:8504448
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_total_replication_buffers:0
mem_replicas_repl_buffer:0
mem_clients_slaves:0
mem_clients_normal:0
mem_cluster_links:0
mem_aof_buffer:0
mem_allocator:jemalloc-5.3.0
mem_overhead_db_hashtable_rehashing:0
active_defrag_running:0
lazyfree_pending_objects:0
lazyfreed_objects:0

# Persistence
loading:0
async_loading:0
current_cow_peak:0
current_cow_size:0
current_cow_size_age:0
current_fork_perc:0.00
current_save_keys_processed:0
current_save_keys_total:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1714701488
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
rdb_saves:1
rdb_last_cow_size:229376
rdb_last_load_keys_expired:0
rdb_last_load_keys_loaded:0
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_rewrites:0
aof_rewrites_consecutive_failures:0
aof_last_write_status:ok
aof_last_cow_size:0
module_fork_in_progress:0
module_fork_last_cow_size:0

# Stats
total_connections_received:3081
total_commands_processed:3080
instantaneous_ops_per_sec:91
total_net_input_bytes:134722
total_net_output_bytes:686934
total_net_repl_input_bytes:0
total_net_repl_output_bytes:0
instantaneous_input_kbps:4.14
instantaneous_output_kbps:1.55
instantaneous_input_repl_kbps:0.00
instantaneous_output_repl_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
expire_cycle_cpu_milliseconds:1829
evicted_keys:0
evicted_clients:0
evicted_scripts:0
total_eviction_exceeded_time:0
current_eviction_exceeded_time:0
keyspace_hits:877
keyspace_misses:98
pubsub_channels:0
pubsub_patterns:0
pubsubshard_channels:0
latest_fork_usec:832
total_forks:5
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
total_active_defrag_time:0
current_active_defrag_time:0
tracking_total_keys:0
tracking_total_items:0
tracking_total_prefixes:0
unexpected_error_replies:0
total_error_replies:55
dump_payload_sanitizations:0
total_reads_processed:6160
total_writes_processed:3085
io_threaded_reads_processed:0
io_threaded_writes_processed:0
client_query_buffer_limit_disconnections:0
client_output_buffer_limit_disconnections:0
reply_buffer_shrinks:3
reply_buffer_expands:0
eventloop_cycles:710861
eventloop_duration_sum:261482066
eventloop_duration_cmd_sum:4662723
instantaneous_eventloop_cycles_per_sec:283
instantaneous_eventloop_duration_usec:595
acl_access_denied_auth:0
acl_access_denied_cmd:0
acl_access_denied_key:0
acl_access_denied_channel:0
acl_access_denied_tls_cert:0

# Replication
role:master
connected_slaves:0
replicas_waiting_psync:0
master_failover_state:no-failover
master_replid:488d931b7e08f8e091f674ea64480165971a25f1
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:68.476389
used_cpu_user:219.408941
used_cpu_sys_children:0.003157
used_cpu_user_children:0.008264
used_cpu_sys_main_thread:68.478353
used_cpu_user_main_thread:219.404508
used_active_time_main_thread:192.003980

# Modules

# Errorstats
errorstat_ERR:count=55

# Cluster
cluster_enabled:0

# Keyspace

Notes

Please note depending on the version of Valkey some of the fields have been added or removed. A robust client application should therefore parse the result of this command by skipping unknown properties, and gracefully handle missing fields.

Here is the description of fields.

Here is the meaning of all fields in the server section:

Here is the meaning of all fields in the clients section:

Here is the meaning of all fields in the memory section:

Ideally, the used_memory_rss value should be only slightly higher than used_memory. When rss >> used, a large difference may mean there is (external) memory fragmentation, which can be evaluated by checking allocator_frag_ratio, allocator_frag_bytes. When used >> rss, it means part of Valkey memory has been swapped off by the operating system: expect some significant latencies.

Because Valkey does not have control over how its allocations are mapped to memory pages, high used_memory_rss is often the result of a spike in memory usage.

When Valkey frees memory, the memory is given back to the allocator, and the allocator may or may not give the memory back to the system. There may be a discrepancy between the used_memory value and memory consumption as reported by the operating system. It may be due to the fact memory has been used and released by Valkey, but not given back to the system. The used_memory_peak value is generally useful to check this point.

Additional introspective information about the server's memory can be obtained by referring to the MEMORY STATS command and the MEMORY DOCTOR.

Here is the meaning of all fields in the persistence section:

rdb_changes_since_last_save refers to the number of operations that produced some kind of changes in the dataset since the last time either SAVE or BGSAVE was called.

If AOF is activated, these additional fields will be added:

If a load operation is on-going, these additional fields will be added:

Here is the meaning of all fields in the stats section:

Here is the meaning of all fields in the replication section:

If the instance is a replica, these additional fields are provided:

If a SYNC operation is on-going, these additional fields are provided:

The following field is always provided:

If the server is configured with the min-replicas-to-write directive, an additional field is provided:

For each replica, the following line is added:

state represents the state of the replica client and can be one of the following strings.

type added in Valkey 8.0, represents the type of the replica client and can be one of the following strings.

Here is the meaning of all fields in the cpu section:

The fields used_active_time_main_thread and used_active_time_io_thread_N were added in Valkey 9.1. They are a better indication than the CPU time metrics of the spare capacity of each thread, because Valkey uses busy-waiting when I/O threads are used, which makes the CPU time appear to be near 100% even if the server has spare capacity for handling more commands.

The active time fields grow linearly with the server load. To understand how to interpret them, consider this example: If the main thread's used active time increases 5 seconds between two INFO calls 10 seconds apart, it means the main thread has spent half of the time executing commands and the other half waiting. It means that it's running at 50% of its capacity.

The commandstats section provides statistics based on the command type, including the number of calls that reached command execution (not rejected), the total CPU time consumed by these commands, the average CPU consumed per command execution, the number of rejected calls (errors prior command execution), and the number of failed calls (errors within the command execution).

For each command type, the following line is added:

The latencystats section provides latency percentile distribution statistics based on the command type.

By default, the exported latency percentiles are the p50, p99, and p999. If you need to change the exported percentiles, use CONFIG SET latency-tracking-info-percentiles "50.0 99.0 99.9".

This section requires the extended latency monitoring feature to be enabled (by default it's enabled). If you need to enable it, use CONFIG SET latency-tracking yes.

For each command type, the following line is added:

The errorstats section enables keeping track of the different errors that occurred within Valkey, based upon the reply error prefix ( The first word after the "-", up to the first space. Example: ERR ).

For each error type, the following line is added:

The sentinel section is only available in Valkey Sentinel instances. It consists of the following fields:

The cluster section currently only contains a unique field:

The modules section contains additional information about loaded modules if the modules provide it. The field part of properties lines in this section is always prefixed with the module's name.

The keyspace section provides statistics on the main dictionary of each database. The statistics are the number of keys, and the number of keys with an expiration.

For each database, the following line is added:

The debug section contains experimental metrics, which might change or get removed in future versions. It won't be included when INFO or INFO ALL are called, and it is returned only when INFO DEBUG is used.

A note about the word slave used in this man page: If not for backward compatibility, the Valkey project no longer uses the words "master" and "slave". Unfortunately in the given commands these words are part of the protocol, so we'll be able to remove such occurrences only when this API will be naturally deprecated.

Modules generated sections: Starting with Valkey 6, modules can inject their info into the INFO command, these are excluded by default even when the all argument is provided (it will include a list of loaded modules but not their generated info fields). To get these you must use either the modules argument or everything.,

json.arrappend

Append one or more values to the array values at the path.

Examples

Enhanced path syntax:

127.0.0.1:6379> JSON.SET k1 . '[[], ["a"], ["a", "b"]]'
OK
127.0.0.1:6379> JSON.ARRAPPEND  k1 $[*] '"c"'
1) (integer) 1
2) (integer) 2
3) (integer) 3
127.0.0.1:6379> JSON.GET k1
"[[\"c\"],[\"a\",\"c\"],[\"a\",\"b\",\"c\"]]"

Restricted path syntax:

127.0.0.1:6379> JSON.SET k1 . '[[], ["a"], ["a", "b"]]'
OK
127.0.0.1:6379> JSON.ARRAPPEND  k1 [-1] '"c"'
(integer) 3
127.0.0.1:6379> JSON.GET k1
"[[],[\"a\"],[\"a\",\"b\",\"c\"]]"

json.arrindex

Search for the first occurrence of a scalar JSON value in the arrays at the path.

Examples

Enhanced path syntax:

127.0.0.1:6379> JSON.SET k1 . '[[], ["a"], ["a", "b"], ["a", "b", "c"]]'
OK
127.0.0.1:6379> JSON.ARRINDEX k1 $[*] '"b"'
1) (integer) -1
2) (integer) -1
3) (integer) 1
4) (integer) 1

Restricted path syntax:

127.0.0.1:6379> JSON.SET k1 . '{"children": ["John", "Jack", "Tom", "Bob", "Mike"]}'
OK
127.0.0.1:6379> JSON.ARRINDEX k1 .children '"Tom"'
(integer) 2

json.arrinsert

Insert one or more values into the array values at path before the index.

Examples

Enhanced path syntax:

127.0.0.1:6379> JSON.SET k1 . '[[], ["a"], ["a", "b"]]'
OK
127.0.0.1:6379> JSON.ARRINSERT k1 $[*] 0 '"c"'
1) (integer) 1
2) (integer) 2
3) (integer) 3
127.0.0.1:6379> JSON.GET k1
"[[\"c\"],[\"c\",\"a\"],[\"c\",\"a\",\"b\"]]"

Restricted path syntax:

127.0.0.1:6379> JSON.SET k1 . '[[], ["a"], ["a", "b"]]'
OK
127.0.0.1:6379> JSON.ARRINSERT k1 . 0 '"c"'
(integer) 4
127.0.0.1:6379> JSON.GET k1
"[\"c\",[],[\"a\"],[\"a\",\"b\"]]"

json.arrlen

Get length of the array at the path.

Examples

Enhanced path syntax:

127.0.0.1:6379> JSON.SET k1 . '[[], [\"a\"], [\"a\", \"b\"], [\"a\", \"b\", \"c\"]]'
(error) SYNTAXERR Failed to parse JSON string due to syntax error
127.0.0.1:6379> JSON.SET k1 . '[[], ["a"], ["a", "b"], ["a", "b", "c"]]'
OK
127.0.0.1:6379> JSON.ARRLEN k1 $[*]
1) (integer) 0
2) (integer) 1
3) (integer) 2
4) (integer) 3

127.0.0.1:6379> JSON.SET k2 . '[[], "a", ["a", "b"], ["a", "b", "c"], 4]'
OK
127.0.0.1:6379> JSON.ARRLEN k2 $[*]
1) (integer) 0
2) (nil)
3) (integer) 2
4) (integer) 3
5) (nil)
127.0.0.1:6379> JSON.SET k1 . '[[], ["a"], ["a", "b"], ["a", "b", "c"]]'
OK
127.0.0.1:6379> JSON.ARRLEN k1 [*]
(integer) 0
127.0.0.1:6379> JSON.ARRLEN k1 $[3]
1) (integer) 3

127.0.0.1:6379> JSON.SET k2 . '[[], "a", ["a", "b"], ["a", "b", "c"], 4]'
OK
127.0.0.1:6379> JSON.ARRLEN k2 [*]
(integer) 0
127.0.0.1:6379> JSON.ARRLEN k2 $[1]
1) (nil)
127.0.0.1:6379> JSON.ARRLEN k2 $[2]
1) (integer) 2

json.arrpop

Remove and return element at the index from the array. Popping an empty array returns null.

Examples

Enhanced path syntax:

127.0.0.1:6379> JSON.SET k1 . '[[], ["a"], ["a", "b"]]'
OK
127.0.0.1:6379> JSON.ARRPOP k1 $[*]
1) (nil)
2) "\"a\""
3) "\"b\""
127.0.0.1:6379> JSON.GET k1
"[[],[],[\"a\"]]"

Restricted path syntax:

127.0.0.1:6379> JSON.SET k1 . '[[], ["a"], ["a", "b"]]'
OK
127.0.0.1:6379> JSON.ARRPOP k1
"[\"a\",\"b\"]"
127.0.0.1:6379> JSON.GET k1
"[[],[\"a\"]]"

127.0.0.1:6379> JSON.SET k2 . '[[], ["a"], ["a", "b"]]'
OK
127.0.0.1:6379> JSON.ARRPOP k2 . 0
"[]"
127.0.0.1:6379> JSON.GET k2
"[[\"a\"],[\"a\",\"b\"]]"

json.arrtrim

Trim arrays at the path so that it becomes subarray [start, end], both inclusive.

Examples

Enhanced path syntax:

127.0.0.1:6379> JSON.SET k1 . '[[], ["a"], ["a", "b"], ["a", "b", "c"]]'
OK
127.0.0.1:6379> JSON.ARRTRIM k1 $[*] 0 1
1) (integer) 0
2) (integer) 1
3) (integer) 2
4) (integer) 2
   127.0.0.1:6379> JSON.GET k1
   "[[],[\"a\"],[\"a\",\"b\"],[\"a\",\"b\"]]"

Restricted path syntax:

127.0.0.1:6379> JSON.SET k1 . '{"children": ["John", "Jack", "Tom", "Bob", "Mike"]}'
OK
127.0.0.1:6379> JSON.ARRTRIM k1 .children 0 1
(integer) 2
127.0.0.1:6379> JSON.GET k1 .children
"[\"John\",\"Jack\"]"

json.clear

Clear the arrays or objects at the path.

Examples

127.0.0.1:6379> JSON.SET k1 . '[[], [0], [0,1], [0,1,2], 1, true, null, "d"]'
OK
127.0.0.1:6379>  JSON.CLEAR k1  $[*]
(integer) 6
127.0.0.1:6379> JSON.CLEAR k1  $[*]
(integer) 0 
127.0.0.1:6379> JSON.SET k2 . '{"children": ["John", "Jack", "Tom", "Bob", "Mike"]}'
OK
127.0.0.1:6379> JSON.CLEAR k2 .children
(integer) 1
127.0.0.1:6379> JSON.GET k2 .children
"[]"

json.debug

Report information. Supported subcommands are:

Examples

Enhanced path syntax:

127.0.0.1:6379> JSON.SET k1 . '[1, 2.3, "foo", true, null, {}, [], {"a":1, "b":2}, [1,2,3]]'
OK
127.0.0.1:6379> JSON.DEBUG MEMORY k1 $[*]
1) (integer) 16
2) (integer) 16
3) (integer) 19
4) (integer) 16
5) (integer) 16
6) (integer) 16
7) (integer) 16
8) (integer) 50
9) (integer) 64
127.0.0.1:6379> JSON.DEBUG FIELDS k1 $[*]
1) (integer) 1
2) (integer) 1
3) (integer) 1
4) (integer) 1
5) (integer) 1
6) (integer) 0
7) (integer) 0
8) (integer) 2
9) (integer) 3

Restricted path syntax:

127.0.0.1:6379> JSON.SET k1 . '{"firstName":"John","lastName":"Smith","age":27,"weight":135.25,"isAlive":true,"address":{"street":"21 2nd Street","city":"New York","state":"NY","zipcode":"10021-3100"},"phoneNumbers":[{"type":"home","number":"212 555-1234"},{"type":"office","number":"646 555-4567"}],"children":[],"spouse":null}'
OK
127.0.0.1:6379> JSON.DEBUG MEMORY k1
(integer) 632
127.0.0.1:6379> JSON.DEBUG MEMORY k1 .phoneNumbers
(integer) 166

127.0.0.1:6379> JSON.DEBUG FIELDS k1
(integer) 19
127.0.0.1:6379> JSON.DEBUG FIELDS k1 .address
(integer) 4
127.0.0.1:6379> JSON.DEBUG HELP
1) JSON.DEBUG MEMORY <key> [path] - report memory size (bytes) of the JSON element. Path defaults to root if not provided.
2) JSON.DEBUG FIELDS <key> [path] - report number of fields in the JSON element. Path defaults to root if not provided.
3) JSON.DEBUG DEPTH <key> - report depth of JSON doc.
3) JSON.DEBUG HELP - print help message.

json.del

Delete the JSON values at the path in a document key. If the path is the root path, it is equivalent to deleting the key from Valkey.

Examples

Enhanced path syntax:

127.0.0.1:6379> JSON.SET k1 . '{"a":{}, "b":{"a":1}, "c":{"a":1, "b":2}, "d":{"a":1, "b":2, "c":3}, "e": [1,2,3,4,5]}'
OK
127.0.0.1:6379> JSON.DEL k1 $.d.*
(integer) 3
127.0.0.1:6379> JSON.GET k1
"{\"a\":{},\"b\":{\"a\":1},\"c\":{\"a\":1,\"b\":2},\"d\":{},\"e\":[1,2,3,4,5]}"
127.0.0.1:6379> JSON.DEL k1 $.e[*]
(integer) 5
127.0.0.1:6379> JSON.GET k1
"{\"a\":{},\"b\":{\"a\":1},\"c\":{\"a\":1,\"b\":2},\"d\":{},\"e\":[]}"

Restricted path syntax:

127.0.0.1:6379> JSON.SET k1 . '{"a":{}, "b":{"a":1}, "c":{"a":1, "b":2}, "d":{"a":1, "b":2, "c":3}, "e": [1,2,3,4,5]}'
OK
127.0.0.1:6379> JSON.DEL k1 .d.*
(integer) 3
127.0.0.1:6379> JSON.GET k1
"{\"a\":{},\"b\":{\"a\":1},\"c\":{\"a\":1,\"b\":2},\"d\":{},\"e\":[1,2,3,4,5]}"
127.0.0.1:6379> JSON.DEL k1 .e[*]
(integer) 5
127.0.0.1:6379> JSON.GET k1
"{\"a\":{},\"b\":{\"a\":1},\"c\":{\"a\":1,\"b\":2},\"d\":{},\"e\":[]}"

json.forget

An alias of JSON.DEL

json.get

Get the serialized JSON at one or multiple paths.

Examples

Enhanced path syntax:

127.0.0.1:6379> JSON.SET k1 . '{"firstName":"John","lastName":"Smith","age":27,"weight":135.25,"isAlive":true,"address":{"street":"21 2nd Street","city":"New York","state":"NY","zipcode":"10021-3100"},"phoneNumbers":[{"type":"home","number":"212 555-1234"},{"type":"office","number":"646 555-4567"}],"children":[],"spouse":null}'
OK
127.0.0.1:6379> JSON.GET k1 $.address.*
"[\"21 2nd Street\",\"New York\",\"NY\",\"10021-3100\"]"
127.0.0.1:6379> JSON.GET k1 indent "\t" space " " NEWLINE "\n" $.address.*
"[\n\t\"21 2nd Street\",\n\t\"New York\",\n\t\"NY\",\n\t\"10021-3100\"\n]"
127.0.0.1:6379> JSON.GET k1 $.firstName $.lastName $.age
"{\"$.firstName\":[\"John\"],\"$.lastName\":[\"Smith\"],\"$.age\":[27]}"

127.0.0.1:6379> JSON.SET k2 . '{"a":{}, "b":{"a":1}, "c":{"a":1, "b":2}}'
OK
127.0.0.1:6379> json.get k2 $..*
"[{},{\"a\":1},{\"a\":1,\"b\":2},1,1,2]"

Restricted path syntax:

127.0.0.1:6379> JSON.SET k1 . '{"firstName":"John","lastName":"Smith","age":27,"weight":135.25,"isAlive":true,"address":{"street":"21 2nd Street","city":"New York","state":"NY","zipcode":"10021-3100"},"phoneNumbers":[{"type":"home","number":"212 555-1234"},{"type":"office","number":"646 555-4567"}],"children":[],"spouse":null}'
OK
127.0.0.1:6379> JSON.GET k1 .address
"{\"street\":\"21 2nd Street\",\"city\":\"New York\",\"state\":\"NY\",\"zipcode\":\"10021-3100\"}"
127.0.0.1:6379> JSON.GET k1 indent "\t" space " " NEWLINE "\n" .address
"{\n\t\"street\": \"21 2nd Street\",\n\t\"city\": \"New York\",\n\t\"state\": \"NY\",\n\t\"zipcode\": \"10021-3100\"\n}"
127.0.0.1:6379> JSON.GET k1 .firstName .lastName .age
"{\".firstName\":\"John\",\".lastName\":\"Smith\",\".age\":27}"

json.mget

Get serialized JSON objects from multiple document keys at the specified path. Return null for non-existent keys or JSON paths.

Examples

Enhanced path syntax:

127.0.0.1:6379> JSON.SET k1 . '{"address":{"street":"21 2nd Street","city":"New York","state":"NY","zipcode":"10021"}}'
OK
127.0.0.1:6379> JSON.SET k2 . '{"address":{"street":"5 main Street","city":"Boston","state":"MA","zipcode":"02101"}}'
OK
127.0.0.1:6379> JSON.SET k3 . '{"address":{"street":"100 Park Ave","city":"Seattle","state":"WA","zipcode":"98102"}}'
OK
127.0.0.1:6379> JSON.MGET k1 k2 k3 $.address.city
1) "[\"New York\"]"
2) "[\"Boston\"]"
3) "[\"Seattle\"]"

Restricted path syntax:

127.0.0.1:6379> JSON.SET k1 . '{"address":{"street":"21 2nd Street","city":"New York","state":"NY","zipcode":"10021"}}'
OK
127.0.0.1:6379> JSON.SET k2 . '{"address":{"street":"5 main Street","city":"Boston","state":"MA","zipcode":"02101"}}'
OK
127.0.0.1:6379> JSON.SET k3 . '{"address":{"street":"100 Park Ave","city":"Seattle","state":"WA","zipcode":"98102"}}'
OK

127.0.0.1:6379> JSON.MGET k1 k2 k3 .address.city
1) "\"New York\""
2) "\"Seattle\""
3) "\"Seattle\""

json.mset

Set JSON values for multiple keys. The operation is atomic. Either all values are set or none is set.

Examples

Enhanced path syntax:

127.0.0.1:6379> JSON.MSET k1 . '[1,2,3,4,5]' k2 . '{"a":{"a":1, "b":2, "c":3}}' k3 . '{"a": [1,2,3,4,5]}'
OK
127.0.0.1:6379> JSON.GET k1
"[1,2,3,4,5]"
127.0.0.1:6379> JSON.GET k2
"{\"a\":{\"a\":1,\"b\":2,\"c\":3}}"
127.0.0.1:6379> JSON.MSET k2 $.a.* '0' k3 $.a[*] '0'
OK
127.0.0.1:6379> JSON.GET k2
"{\"a\":{\"a\":0,\"b\":0,\"c\":0}}"
127.0.0.1:6379> JSON.GET k3
"{\"a\":[0,0,0,0,0]}"

Restricted path syntax:

127.0.0.1:6379> JSON.MSET k1 . '{"name": "John","address": {"street": "123 Main St","city": "Springfield"},"phones": ["555-1234","555-5678"]}'
OK
127.0.0.1:6379> JSON.MSET k1 .address.street '"21 2nd Street"' k1 .address.city '"New York"'
OK
127.0.0.1:6379> JSON.GET k1 .address.street
"\"21 2nd Street\""
127.0.0.1:6379> JSON.GET k1 .address.city
"\"New York\""