diff --git a/docs.json b/docs.json index 0891e59a..2ca3cbf5 100644 --- a/docs.json +++ b/docs.json @@ -939,6 +939,393 @@ ] } ] + }, + { + "group": "Command Reference", + "pages": [ + "redis/commands/overview", + { + "group": "Bitmap", + "pages": [ + "redis/commands/bitmap/overview", + "redis/commands/bitmap/bitcount", + "redis/commands/bitmap/bitfield", + "redis/commands/bitmap/bitfield-ro", + "redis/commands/bitmap/bitop", + "redis/commands/bitmap/bitpos", + "redis/commands/bitmap/getbit", + "redis/commands/bitmap/setbit" + ] + }, + { + "group": "Connection", + "pages": [ + "redis/commands/connection/overview", + "redis/commands/connection/auth", + "redis/commands/connection/client-getname", + "redis/commands/connection/client-id", + "redis/commands/connection/client-info", + "redis/commands/connection/client-list", + "redis/commands/connection/client-setinfo", + "redis/commands/connection/client-setname", + "redis/commands/connection/echo", + "redis/commands/connection/hello", + "redis/commands/connection/ping", + "redis/commands/connection/quit", + "redis/commands/connection/reset", + "redis/commands/connection/select" + ] + }, + { + "group": "Functions", + "pages": [ + "redis/commands/functions/overview", + "redis/commands/functions/fcall", + "redis/commands/functions/fcall-ro", + "redis/commands/functions/function-delete", + "redis/commands/functions/function-flush", + "redis/commands/functions/function-kill", + "redis/commands/functions/function-list", + "redis/commands/functions/function-load", + "redis/commands/functions/function-stats" + ] + }, + { + "group": "Generic", + "pages": [ + "redis/commands/generic/overview", + "redis/commands/generic/copy", + "redis/commands/generic/del", + "redis/commands/generic/dump", + "redis/commands/generic/exists", + "redis/commands/generic/expire", + "redis/commands/generic/expireat", + "redis/commands/generic/expiretime", + "redis/commands/generic/keys", + "redis/commands/generic/memory-usage", + "redis/commands/generic/persist", + "redis/commands/generic/pexpire", + "redis/commands/generic/pexpireat", + "redis/commands/generic/pexpiretime", + "redis/commands/generic/pttl", + "redis/commands/generic/randomkey", + "redis/commands/generic/rename", + "redis/commands/generic/renamenx", + "redis/commands/generic/restore", + "redis/commands/generic/scan", + "redis/commands/generic/touch", + "redis/commands/generic/ttl", + "redis/commands/generic/type", + "redis/commands/generic/unlink", + "redis/commands/generic/wait", + "redis/commands/generic/waitaof" + ] + }, + { + "group": "Geo", + "pages": [ + "redis/commands/geo/overview", + "redis/commands/geo/geoadd", + "redis/commands/geo/geodist", + "redis/commands/geo/geohash", + "redis/commands/geo/geopos", + "redis/commands/geo/georadius", + "redis/commands/geo/georadius-ro", + "redis/commands/geo/georadiusbymember", + "redis/commands/geo/georadiusbymember-ro", + "redis/commands/geo/geosearch", + "redis/commands/geo/geosearchstore" + ] + }, + { + "group": "Hash", + "pages": [ + "redis/commands/hash/overview", + "redis/commands/hash/hdel", + "redis/commands/hash/hexists", + "redis/commands/hash/hexpire", + "redis/commands/hash/hexpireat", + "redis/commands/hash/hexpiretime", + "redis/commands/hash/hget", + "redis/commands/hash/hgetall", + "redis/commands/hash/hgetdel", + "redis/commands/hash/hgetex", + "redis/commands/hash/hincrby", + "redis/commands/hash/hincrbyfloat", + "redis/commands/hash/hkeys", + "redis/commands/hash/hlen", + "redis/commands/hash/hmget", + "redis/commands/hash/hmset", + "redis/commands/hash/hpersist", + "redis/commands/hash/hpexpire", + "redis/commands/hash/hpexpireat", + "redis/commands/hash/hpexpiretime", + "redis/commands/hash/hpttl", + "redis/commands/hash/hrandfield", + "redis/commands/hash/hscan", + "redis/commands/hash/hset", + "redis/commands/hash/hsetex", + "redis/commands/hash/hsetnx", + "redis/commands/hash/hstrlen", + "redis/commands/hash/httl", + "redis/commands/hash/hvals" + ] + }, + { + "group": "HyperLogLog", + "pages": [ + "redis/commands/hyperloglog/overview", + "redis/commands/hyperloglog/pfadd", + "redis/commands/hyperloglog/pfcount", + "redis/commands/hyperloglog/pfmerge" + ] + }, + { + "group": "JSON", + "pages": [ + "redis/commands/json/overview", + "redis/commands/json/json-arrappend", + "redis/commands/json/json-arrindex", + "redis/commands/json/json-arrinsert", + "redis/commands/json/json-arrlen", + "redis/commands/json/json-arrpop", + "redis/commands/json/json-arrtrim", + "redis/commands/json/json-clear", + "redis/commands/json/json-del", + "redis/commands/json/json-debug", + "redis/commands/json/json-forget", + "redis/commands/json/json-get", + "redis/commands/json/json-merge", + "redis/commands/json/json-mget", + "redis/commands/json/json-mset", + "redis/commands/json/json-numincrby", + "redis/commands/json/json-nummultby", + "redis/commands/json/json-objkeys", + "redis/commands/json/json-objlen", + "redis/commands/json/json-resp", + "redis/commands/json/json-set", + "redis/commands/json/json-strappend", + "redis/commands/json/json-strlen", + "redis/commands/json/json-toggle", + "redis/commands/json/json-type" + ] + }, + { + "group": "List", + "pages": [ + "redis/commands/list/overview", + "redis/commands/list/blmove", + "redis/commands/list/blmpop", + "redis/commands/list/blpop", + "redis/commands/list/brpop", + "redis/commands/list/brpoplpush", + "redis/commands/list/lindex", + "redis/commands/list/linsert", + "redis/commands/list/llen", + "redis/commands/list/lmove", + "redis/commands/list/lmpop", + "redis/commands/list/lpop", + "redis/commands/list/lpos", + "redis/commands/list/lpush", + "redis/commands/list/lpushx", + "redis/commands/list/lrange", + "redis/commands/list/lrem", + "redis/commands/list/lset", + "redis/commands/list/ltrim", + "redis/commands/list/rpop", + "redis/commands/list/rpoplpush", + "redis/commands/list/rpush", + "redis/commands/list/rpushx" + ] + }, + { + "group": "Pub/Sub", + "pages": [ + "redis/commands/pub-sub/overview", + "redis/commands/pub-sub/psubscribe", + "redis/commands/pub-sub/publish", + "redis/commands/pub-sub/pubsub", + "redis/commands/pub-sub/punsubscribe", + "redis/commands/pub-sub/subscribe", + "redis/commands/pub-sub/unsubscribe" + ] + }, + { + "group": "Scripting", + "pages": [ + "redis/commands/scripting/overview", + "redis/commands/scripting/eval", + "redis/commands/scripting/eval-ro", + "redis/commands/scripting/evalsha", + "redis/commands/scripting/evalsha-ro", + "redis/commands/scripting/script-exists", + "redis/commands/scripting/script-flush", + "redis/commands/scripting/script-kill", + "redis/commands/scripting/script-load" + ] + }, + { + "group": "Search", + "pages": [ + "redis/commands/search/overview", + "redis/commands/search/search-create", + "redis/commands/search/search-reindex", + "redis/commands/search/search-drop", + "redis/commands/search/search-describe", + "redis/commands/search/search-waitindexing", + "redis/commands/search/search-listindexes", + "redis/commands/search/search-query", + "redis/commands/search/search-count", + "redis/commands/search/search-aggregate", + "redis/commands/search/search-aliasadd", + "redis/commands/search/search-aliasdel", + "redis/commands/search/search-listaliases" + ] + }, + { + "group": "Server", + "pages": [ + "redis/commands/server/overview", + "redis/commands/server/acl", + "redis/commands/server/command", + "redis/commands/server/config-get", + "redis/commands/server/config-set", + "redis/commands/server/dbsize", + "redis/commands/server/flushall", + "redis/commands/server/flushdb", + "redis/commands/server/info", + "redis/commands/server/monitor", + "redis/commands/server/time" + ] + }, + { + "group": "Set", + "pages": [ + "redis/commands/set/overview", + "redis/commands/set/sadd", + "redis/commands/set/scard", + "redis/commands/set/sdiff", + "redis/commands/set/sdiffstore", + "redis/commands/set/sinter", + "redis/commands/set/sintercard", + "redis/commands/set/sinterstore", + "redis/commands/set/sismember", + "redis/commands/set/smembers", + "redis/commands/set/smismember", + "redis/commands/set/smove", + "redis/commands/set/spop", + "redis/commands/set/srandmember", + "redis/commands/set/srem", + "redis/commands/set/sscan", + "redis/commands/set/sunion", + "redis/commands/set/sunionstore" + ] + }, + { + "group": "Sorted Set", + "pages": [ + "redis/commands/sorted-set/overview", + "redis/commands/sorted-set/bzmpop", + "redis/commands/sorted-set/bzpopmax", + "redis/commands/sorted-set/bzpopmin", + "redis/commands/sorted-set/zadd", + "redis/commands/sorted-set/zcard", + "redis/commands/sorted-set/zcount", + "redis/commands/sorted-set/zdiff", + "redis/commands/sorted-set/zdiffstore", + "redis/commands/sorted-set/zincrby", + "redis/commands/sorted-set/zinter", + "redis/commands/sorted-set/zintercard", + "redis/commands/sorted-set/zinterstore", + "redis/commands/sorted-set/zlexcount", + "redis/commands/sorted-set/zmpop", + "redis/commands/sorted-set/zmscore", + "redis/commands/sorted-set/zpopmax", + "redis/commands/sorted-set/zpopmin", + "redis/commands/sorted-set/zrandmember", + "redis/commands/sorted-set/zrange", + "redis/commands/sorted-set/zrangebylex", + "redis/commands/sorted-set/zrangebyscore", + "redis/commands/sorted-set/zrangestore", + "redis/commands/sorted-set/zrank", + "redis/commands/sorted-set/zrem", + "redis/commands/sorted-set/zremrangebylex", + "redis/commands/sorted-set/zremrangebyrank", + "redis/commands/sorted-set/zremrangebyscore", + "redis/commands/sorted-set/zrevrange", + "redis/commands/sorted-set/zrevrangebylex", + "redis/commands/sorted-set/zrevrangebyscore", + "redis/commands/sorted-set/zrevrank", + "redis/commands/sorted-set/zscan", + "redis/commands/sorted-set/zscore", + "redis/commands/sorted-set/zunion", + "redis/commands/sorted-set/zunionstore" + ] + }, + { + "group": "Streams", + "pages": [ + "redis/commands/streams/overview", + "redis/commands/streams/xack", + "redis/commands/streams/xackdel", + "redis/commands/streams/xadd", + "redis/commands/streams/xautoclaim", + "redis/commands/streams/xclaim", + "redis/commands/streams/xdel", + "redis/commands/streams/xdelex", + "redis/commands/streams/xgroup", + "redis/commands/streams/xinfo-consumers", + "redis/commands/streams/xinfo-groups", + "redis/commands/streams/xinfo-stream", + "redis/commands/streams/xlen", + "redis/commands/streams/xpending", + "redis/commands/streams/xrange", + "redis/commands/streams/xread", + "redis/commands/streams/xreadgroup", + "redis/commands/streams/xrevrange", + "redis/commands/streams/xtrim" + ] + }, + { + "group": "String", + "pages": [ + "redis/commands/string/overview", + "redis/commands/string/append", + "redis/commands/string/decr", + "redis/commands/string/decrby", + "redis/commands/string/delex", + "redis/commands/string/digest", + "redis/commands/string/get", + "redis/commands/string/getdel", + "redis/commands/string/getex", + "redis/commands/string/getrange", + "redis/commands/string/getset", + "redis/commands/string/incr", + "redis/commands/string/incrby", + "redis/commands/string/incrbyfloat", + "redis/commands/string/mget", + "redis/commands/string/mset", + "redis/commands/string/msetnx", + "redis/commands/string/psetex", + "redis/commands/string/set", + "redis/commands/string/setex", + "redis/commands/string/setnx", + "redis/commands/string/setrange", + "redis/commands/string/strlen" + ] + }, + { + "group": "Transactions", + "pages": [ + "redis/commands/transactions/overview", + "redis/commands/transactions/discard", + "redis/commands/transactions/exec", + "redis/commands/transactions/multi", + "redis/commands/transactions/unwatch", + "redis/commands/transactions/watch" + ] + } + ] } ] }, @@ -1953,6 +2340,10 @@ "source": "/redis/overall/rediscompatibility", "destination": "/redis/overall/compatibility" }, + { + "source": "/redis/search/command-reference", + "destination": "/redis/commands/search/overview" + }, { "source": "/docs/redis/overall/rediscompatibility", "destination": "/redis/overall/compatibility" diff --git a/llms-full.txt b/llms-full.txt index 8ab508be..1de7dae5 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -16964,6 +16964,48347 @@ For debugging or monitoring purposes, you can use Realtime Dashboard in console. +# BITCOUNT +Source: https://upstash.com/docs/redis/commands/bitmap/bitcount + +Use `BITCOUNT` to count the bits set to 1 in the string stored at a key. + +Without a range the whole value is counted. `` and `` restrict the count to a part of the value and are interpreted as byte offsets by default, or as bit offsets when `BIT` is given. Both ends are inclusive and may be negative to count backwards from the end of the value, where `-1` is the last byte or bit. A missing key is treated as an empty string and returns `0`. + +`BITCOUNT` is the usual way to read a bitmap built with [`SETBIT`](/docs/redis/commands/bitmap/setbit), for example to count how many users were active on a given day when each user has a fixed bit position. + +## Syntax + +```redis +BITCOUNT [ [BYTE | BIT]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| ` [BYTE \| BIT]` | No | No | Range to count. Offsets are byte-based unless `BIT` is given; negative offsets count from the end. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +BITCOUNT my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const bits = await redis.bitcount(key); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.bitcount("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.bitcount("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.bitCount("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.bitcount("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.BitCount(context.Background(), "my-key", nil).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.bitcount("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.bitcount("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# BITFIELD +Source: https://upstash.com/docs/redis/commands/bitmap/bitfield + +Use `BITFIELD` to treat a string as an array of packed integers and run several operations on it in a single atomic call. + +Every operation names an encoding and a bit offset. The encoding is `u` for unsigned integers (up to 63 bits) or `i` for signed integers (up to 64 bits). The offset is counted in bits from the start of the value or, when prefixed with `#`, in units of the encoding width, so `#2` with `u8` addresses the third 8-bit field. The string grows automatically with zero bits when an operation addresses an offset past its current end. + +`GET` reads a field, `SET` writes one and returns its previous value, and `INCRBY` adds a possibly negative increment and returns the new value. `OVERFLOW` sets how the `SET` and `INCRBY` operations that follow it behave when a value does not fit the encoding: `WRAP` wraps around like modular arithmetic and is the default, `SAT` saturates at the minimum or maximum of the encoding, and `FAIL` leaves the field unchanged and returns null for that operation. The reply is an array with one entry per operation, in the order the operations were given. + +Packing many small counters into a single key this way saves memory and keeps the whole update atomic, which makes it a good fit for rate limiters and compact per-user counters. + +## Syntax + +```redis +BITFIELD + [GET | + [OVERFLOW WRAP | SAT | FAIL] + (SET | + INCRBY ) + [GET | + [OVERFLOW WRAP | SAT | FAIL] + (SET | + INCRBY ) + ...]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `(GET \| [OVERFLOW WRAP \| SAT \| FAIL] (SET \| INCRBY ))` | No | Yes | An operation on a field of `` (`u` unsigned up to 63 bits, or `i` signed up to 64 bits) at `` bits, or at `#` to address the n-th field of that width: `GET` reads it, `SET` writes it and returns the previous value, and `INCRBY` adds an increment and returns the new value. `OVERFLOW` sets how the `SET` and `INCRBY` operations after it handle a value that does not fit: `WRAP` wraps around (the default), `SAT` saturates at the encoding's limits, and `FAIL` leaves the field unchanged and returns null. Repeat to run several operations in one atomic call. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer or null replies, one per subcommand | +| RESP3 | Array of integer or null replies, one per subcommand | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +BITFIELD my-key GET u8 0 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.bitfield("my-key").get("u8", 0).exec(); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.bitfield("my-key").get("u8", 0).execute() +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.bitfield("my-key", "GET", "u8", "0"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.bitField("my-key", [{ operation: "GET", encoding: "u8", offset: 0 }]); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.bitfield("my-key").get("u8", 0).execute() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.BitField(context.Background(), "my-key", "GET", "u8", 0).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.bitfield("my-key", "GET", "u8", "0"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("BITFIELD"); + command.arg("my-key"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# BITFIELD_RO +Source: https://upstash.com/docs/redis/commands/bitmap/bitfield-ro + +Use `BITFIELD_RO` to read one or more bitfield values without modifying the key. + +It is the read-only form of [`BITFIELD`](/docs/redis/commands/bitmap/bitfield) and accepts `GET` operations only, so it is safe to run on replicas and from read-only scripts. Each `GET` names an encoding, `u` for unsigned or `i` for signed integers, and a bit offset that can be written as `#` to address the n-th field of that width. The reply holds one integer per `GET`, and any part of a field that lies past the end of the stored string reads as zero. + +## Syntax + +```redis +BITFIELD_RO [GET [GET ...]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `GET ` | No | Yes | Read the value at `` using ``, such as `u8` or `i16`. Repeat to read several fields. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer or null replies, one per subcommand | +| RESP3 | Array of integer or null replies, one per subcommand | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +BITFIELD_RO my-key GET u8 0 +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.bitfield_ro("my-key").get("u8", 0).execute() +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.bitfield_ro("my-key", "GET", "u8", "0"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.bitFieldRo("my-key", [{ encoding: "u8", offset: 0 }]); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.bitfield_ro("my-key", "u8", 0) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.BitFieldRO(context.Background(), "my-key", "GET", "u8", 0).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.bitfieldReadonly("my-key", "GET", "u8", "0"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("BITFIELD_RO"); + command.arg("my-key"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# BITOP +Source: https://upstash.com/docs/redis/commands/bitmap/bitop + +Use `BITOP` to combine several strings with a bitwise operation and store the result in another key. + +Source strings are combined bit by bit, and shorter ones are treated as if they were padded with zero bits up to the length of the longest input, so the destination always ends up as long as the longest source. A missing key counts as an empty string, and if the result is empty the destination key is deleted. The reply is the length of the stored value in bytes. + +`AND`, `OR`, and `XOR` accept any number of source keys and `NOT` accepts exactly one. The remaining operators compare the first key with the rest: `DIFF` keeps the bits set in the first key and in none of the others, `DIFF1` keeps the bits set in at least one of the other keys but not in the first, `ANDOR` keeps the bits set in the first key and in at least one of the others, and `ONE` keeps the bits set in exactly one of the source keys. `DIFF`, `DIFF1`, and `ANDOR` each require at least two source keys. + +This is how bitmaps are used as sets: with one bit per user, `AND` gives users present in every bitmap and `OR` gives users present in any of them, and [`BITCOUNT`](/docs/redis/commands/bitmap/bitcount) then turns the result into a number. + +## Syntax + +```redis +BITOP (AND | OR | XOR | NOT | DIFF | DIFF1 | ANDOR | ONE) [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `(AND \| OR \| XOR \| NOT \| DIFF \| DIFF1 \| ANDOR \| ONE)` | Yes | No | The bitwise operation to apply. `AND`, `OR`, and `XOR` combine any number of source keys and `NOT` inverts exactly one. The rest compare the first key with the others: `DIFF` keeps bits set in the first key and in none of the others, `DIFF1` keeps bits set in at least one of the others but not in the first, `ANDOR` keeps bits set in the first key and in at least one of the others, and `ONE` keeps bits set in exactly one source key. | +| `` | Yes | No | Redis key used as destkey. | +| `` | Yes | Yes | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +BITOP AND destination-key source-key-1 source-key-2 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +// AND operation +await redis.bitop("and", "destKey", "sourceKey1", "sourceKey2"); + +// OR operation +await redis.bitop("or", "destKey", "sourceKey1", "sourceKey2"); + +// XOR operation +await redis.bitop("xor", "destKey", "sourceKey1", "sourceKey2"); + +// NOT operation (only accepts one source key) +await redis.bitop("not", "destKey", "sourceKey"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.bitop("AND", "destination-key", "source-key-1", "source-key-2") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.bitop("AND", "destination-key", "source-key-1", "source-key-2"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.bitOp("AND", "destination-key", ["source-key-1", "source-key-2"]); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.bitop("AND", "destination-key", "source-key-1", "source-key-2") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.BitOpAnd(context.Background(), "destination-key", "source-key-1", "source-key-2").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.bitop(redis.clients.jedis.args.BitOP.AND, "destination-key", "source-key-1", "source-key-2"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.bit_and("destination-key", &["source-key-1", "source-key-2"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# BITPOS +Source: https://upstash.com/docs/redis/commands/bitmap/bitpos + +Use `BITPOS` to find the position of the first bit set to `0` or `1` in a string. + +The whole value is searched unless `` and `` are given, and those are byte offsets by default or bit offsets when `BIT` is given. Both ends are inclusive and may be negative to count backwards from the end of the value. The reply is always an absolute bit position counted from the start of the string, or `-1` when no matching bit is found. + +One edge case is worth remembering: when you look for a `0` in a string of all ones and give no explicit end, the reply is the position of the first bit past the end of the string, because the value is treated as if it were followed by an infinite run of zero bits. Bounding the search with an explicit range returns `-1` in the same situation. + +## Syntax + +```redis +BITPOS [ [ [BYTE | BIT]]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Bit value to look for: `0` or `1`. | +| ` [ [BYTE \| BIT]]` | No | No | Range to search. Offsets are byte-based unless `BIT` is given; negative offsets count from the end. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: the position of the first matching bit, or `-1` | +| RESP3 | Integer: the position of the first matching bit, or `-1` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +BITPOS my-key 1 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.bitpos("key", 1); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.bitpos("my-key", 1) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.bitpos("my-key", "1"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.bitPos("my-key", 1); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.bitpos("my-key", 1) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.BitPos(context.Background(), "my-key", 1).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.bitpos("my-key", true); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("BITPOS"); + command.arg("my-key"); + command.arg("1"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# GETBIT +Source: https://upstash.com/docs/redis/commands/bitmap/getbit + +Use `GETBIT` to read a single bit of the string stored at a key. + +The offset is counted in bits from the start of the value, so offset `0` is the most significant bit of the first byte. When the key does not exist, or the offset lies past the end of the stored string, the bit reads as `0` rather than producing an error. + +## Syntax + +```redis +GETBIT +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Zero-based bit offset to read. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: the bit at the offset, `0` or `1` | +| RESP3 | Integer: the bit at the offset, `0` or `1` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +GETBIT my-key 0 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const bit = await redis.getbit(key, 4); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.getbit("my-key", 0) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.getbit("my-key", "0"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.getBit("my-key", 0); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.getbit("my-key", 0) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.GetBit(context.Background(), "my-key", 0).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.getbit("my-key", 0); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.getbit("my-key", 0)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# Bitmap commands +Source: https://upstash.com/docs/redis/commands/bitmap/overview + + +Count set bits in a string +Perform arbitrary bitfield operations +Read-only bitfield operations +Perform bitwise operations between strings +Find first bit set or clear in a string +Get the bit value at offset +Set or clear the bit at offset + + +# SETBIT +Source: https://upstash.com/docs/redis/commands/bitmap/setbit + +Use `SETBIT` to set a single bit of the string stored at a key to `0` or `1`. + +The offset is counted in bits from the start of the value and the reply is the bit's previous value. If the key does not exist, or the offset lies past the end of the current value, the string is first extended with zero bits, so writing to a large offset allocates every byte up to it. Keep offsets dense, for example by mapping each user to a small sequential id. + +Bitmaps built this way are read back with [`GETBIT`](/docs/redis/commands/bitmap/getbit), counted with [`BITCOUNT`](/docs/redis/commands/bitmap/bitcount), and combined with [`BITOP`](/docs/redis/commands/bitmap/bitop). + +## Syntax + +```redis +SETBIT +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Zero-based bit offset to write. | +| `` | Yes | No | Bit value to write: `0` or `1`. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: the previous bit at the offset, `0` or `1` | +| RESP3 | Integer: the previous bit at the offset, `0` or `1` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +SETBIT my-key 0 1 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const originalBit = await redis.setbit(key, 4, 1); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.setbit("my-key", 0, 1) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.setbit("my-key", "0", "1"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.setBit("my-key", 0, 1); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.setbit("my-key", 0, 1) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.SetBit(context.Background(), "my-key", 0, 1).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.setbit("my-key", 0, true); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.setbit("my-key", 0, true)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# AUTH +Source: https://upstash.com/docs/redis/commands/connection/auth + +Use `AUTH` to authenticate the current connection, with a password alone or with a username and password when ACL users are configured. + +Until the connection is authenticated the server rejects other commands with an error. Client libraries usually send `AUTH` for you as part of connecting when the credentials are part of the connection string, so applications rarely call it directly. The password is sent to the server on every connection, which is why Upstash endpoints use TLS. + +## Syntax + +```redis +AUTH [] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | No | No | Username to authenticate as. | +| `` | Yes | No | Password to authenticate with. | + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +AUTH password +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.auth("password"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.auth({ password: "password" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.auth("password") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Do(context.Background(), "AUTH", "password").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.auth("password"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("AUTH"); + command.arg("password"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# CLIENT GETNAME +Source: https://upstash.com/docs/redis/commands/connection/client-getname + +Use `CLIENT GETNAME` to read the name assigned to the current connection with [`CLIENT SETNAME`](/docs/redis/commands/connection/client-setname). + +Connections start without a name and the reply is null until one is set. The name belongs to a single connection and is lost when it closes; it exists to make connections recognizable in [`CLIENT LIST`](/docs/redis/commands/connection/client-list) output when you are debugging which part of an application is doing what. + +## Syntax + +```redis +CLIENT GETNAME +``` + +## Arguments + +This command takes no arguments. + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. +* This command can expose administrative information or make a broad destructive change. Restrict it to trusted code paths. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Null bulk string or null array or Bulk string | +| RESP3 | Null or Bulk string | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +CLIENT GETNAME +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.client("GETNAME"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.clientGetName(); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.client_getname() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.ClientGetName(context.Background()).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.clientGetname(); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.client_getname()?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# CLIENT ID +Source: https://upstash.com/docs/redis/commands/connection/client-id + +Use `CLIENT ID` to get the unique identifier the server assigned to the current connection. + +IDs are integers that never repeat and always increase, so a larger ID means a connection that was established later. The ID identifies this connection in [`CLIENT LIST`](/docs/redis/commands/connection/client-list) output, which makes it useful when correlating application logs with server-side connection state. + +## Syntax + +```redis +CLIENT ID +``` + +## Arguments + +This command takes no arguments. + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. +* This command can expose administrative information or make a broad destructive change. Restrict it to trusted code paths. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +CLIENT ID +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.client("ID"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.clientId(); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.client_id() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.ClientID(context.Background()).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.clientId(); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.client_id()?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# CLIENT INFO +Source: https://upstash.com/docs/redis/commands/connection/client-info + +Use `CLIENT INFO` to get a line of statistics about the connection issuing the command. + +The reply is a single line of space-separated `field=value` pairs describing the connection: its id, name, address, age, idle time, the number of commands it has run, and the last command it executed. It reports the same fields as one line of [`CLIENT LIST`](/docs/redis/commands/connection/client-list), limited to your own connection, which makes it a cheap way to confirm what the server thinks of the connection you are on. Parse it defensively, since fields can be added over time. + +## Syntax + +```redis +CLIENT INFO +``` + +## Arguments + +This command takes no arguments. + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. +* This command can expose administrative information or make a broad destructive change. Restrict it to trusted code paths. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string | +| RESP3 | Bulk string | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +CLIENT INFO +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.client("INFO"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.clientInfo(); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.client_info() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.ClientInfo(context.Background()).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.clientInfo(); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("CLIENT"); + command.arg("INFO"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# CLIENT LIST +Source: https://upstash.com/docs/redis/commands/connection/client-list + +Use `CLIENT LIST` to get one line of statistics for every client connection to the server. + +Each line holds space-separated `field=value` pairs with the connection's id, name, address, age, idle time, protocol version, and last command, so the reply gives a snapshot of who is connected and what they are doing. It is the usual starting point for tracking down connection leaks and idle connections. The reply grows with the number of clients, so avoid calling it on a hot path, and parse it defensively because fields can be added over time. + +## Syntax + +```redis +CLIENT LIST +``` + +## Arguments + +This command takes no arguments. + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. +* This command can expose administrative information or make a broad destructive change. Restrict it to trusted code paths. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string | +| RESP3 | Bulk string | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +CLIENT LIST +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.client("LIST"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.clientList(); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.client_list() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.ClientList(context.Background()).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.clientList(); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("CLIENT"); + command.arg("LIST"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# CLIENT SETINFO +Source: https://upstash.com/docs/redis/commands/connection/client-setinfo + +Use `CLIENT SETINFO` to attach library identification to the current connection. + +`LIB-NAME` records the name of the client library and `LIB-VER` its version. Both values then appear in [`CLIENT INFO`](/docs/redis/commands/connection/client-info) and [`CLIENT LIST`](/docs/redis/commands/connection/client-list) output, which makes it possible to tell which application or SDK version owns a connection. Most client libraries send this during the handshake, so applications rarely call it themselves. + +## Syntax + +```redis +CLIENT SETINFO +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `LIB-NAME \| LIB-VER` | Yes | No | Attribute to update: the client library name or version. | +| `value` | Yes | No | Value to store for the selected client attribute. | + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. +* This command can expose administrative information or make a broad destructive change. Restrict it to trusted code paths. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +CLIENT SETINFO LIB-NAME my-client +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("CLIENT", "SETINFO", "LIB-NAME", "my-client"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.sendCommand(["CLIENT", "SETINFO", "LIB-NAME", "my-client"]); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.client_setinfo("LIB-NAME", "my-client") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Do(context.Background(), "CLIENT", "SETINFO", "LIB-NAME", "my-client").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.clientSetInfo(redis.clients.jedis.args.ClientAttributeOption.LIB_NAME, "my-client"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("CLIENT"); + command.arg("SETINFO"); + command.arg("LIB-NAME"); + command.arg("my-client"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# CLIENT SETNAME +Source: https://upstash.com/docs/redis/commands/connection/client-setname + +Use `CLIENT SETNAME` to label the current connection with a name of your choice. + +The name shows up in [`CLIENT LIST`](/docs/redis/commands/connection/client-list) and [`CLIENT INFO`](/docs/redis/commands/connection/client-info) output, which is handy when several components of an application share one database and you want to tell their connections apart. The name may not contain spaces or newlines, each call replaces the previous name, and passing an empty string clears it. It lives only as long as the connection. + +## Syntax + +```redis +CLIENT SETNAME +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `connection-name` | Yes | No | Name to associate with this TCP connection. | + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. +* This command can expose administrative information or make a broad destructive change. Restrict it to trusted code paths. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +CLIENT SETNAME worker-1 +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.client("SETNAME", "worker-1"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.clientSetName("worker-1"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.client_setname("worker-1") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Do(context.Background(), "CLIENT", "SETNAME", "worker-1").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.clientSetname("worker-1"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.client_setname("worker-1")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# ECHO +Source: https://upstash.com/docs/redis/commands/connection/echo + +Use `ECHO` to have the server send the given message back unchanged. + +The command performs no work beyond the round trip, which makes it a simple way to verify that a connection is alive and that values survive the client library's encoding and decoding. For plain liveness checks [`PING`](/docs/redis/commands/connection/ping) is the more common choice. + +## Syntax + +```redis +ECHO +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Message payload. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string | +| RESP3 | Bulk string | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +ECHO hello +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const response = await redis.echo("hello world"); +console.log(response); // "hello world" +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.echo("hello") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.echo("hello"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.echo("hello"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.echo("hello") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Echo(context.Background(), "hello").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.echo("hello"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("ECHO"); + command.arg("hello"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HELLO +Source: https://upstash.com/docs/redis/commands/connection/hello + +Use `HELLO` to negotiate the protocol version of the connection and read the server handshake information. + +Passing `` switches the connection to RESP2 or RESP3. RESP3 adds native map, set, double, and push replies, so commands such as [`HGETALL`](/docs/redis/commands/hash/hgetall) or [`CONFIG GET`](/docs/redis/commands/server/config-get) come back as maps instead of flat arrays, and pub/sub messages arrive as push replies that do not block ordinary commands. `AUTH` authenticates in the same call and `SETNAME` names the connection, which lets a client complete its handshake in one round trip. + +Called without arguments, `HELLO` only reports the server version, the protocol in use, the connection id, and the current role, leaving the protocol unchanged. + +## Syntax + +```redis +HELLO + [ + [AUTH ] + [SETNAME ]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| ` [AUTH ] [SETNAME ]` | No | No | Protocol version to switch to, optionally with credentials and a connection name. | + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Flat array of alternating keys and values | +| RESP3 | Map | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HELLO +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hello(); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hello(); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hello() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Do(context.Background(), "HELLO").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; +import java.nio.charset.StandardCharsets; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.commands.ProtocolCommand; + +ProtocolCommand command = () -> "HELLO".getBytes(StandardCharsets.UTF_8); +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.sendCommand(command); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("HELLO"); + + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# Connection commands +Source: https://upstash.com/docs/redis/commands/connection/overview + + +Authenticate to the server +Get the current connection name +Get the current client ID +Get info about current connection +List all client connections +Set client connection attributes +Set the connection name +Echo the given string +Handshake with Redis protocol +Ping the server +Close the connection +Reset the connection +Select the database by index + + +# PING +Source: https://upstash.com/docs/redis/commands/connection/ping + +Use `PING` to check that the connection and the server are alive. + +Without arguments the server replies `PONG`. With a message it echoes that message back instead, which lets a client match a reply to the exact request that produced it. `PING` is the standard health check for a connection pool, both to test a connection before handing it out and to keep an otherwise idle connection from being closed by intermediate proxies. It also works while the connection is subscribed to channels, where it doubles as a keepalive. + +## Syntax + +```redis +PING [] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | No | No | Message payload. | + +## Important points + +* Without arguments the reply is `PONG`; with a message, the message is echoed back as a bulk string. +* While the connection is subscribed under RESP2, `PING` replies with a two-element array holding `pong` and the message instead. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `PONG`, or the message as a bulk string; a two-element `pong`/message array while subscribed | +| RESP3 | Simple string `PONG`, or the message as a bulk string | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PING +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const response = await redis.ping(); +console.log(response); // "PONG" +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.ping() +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.ping(); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.ping(); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.ping() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Ping(context.Background()).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.ping(); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.ping()?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# QUIT +Source: https://upstash.com/docs/redis/commands/connection/quit + + + Prefer closing the connection from the client in new code, which avoids leaving `TIME_WAIT` sockets on the server. + + +Use `QUIT` to ask the server to close the connection once all pending replies have been sent. + +The server replies `OK` and then terminates the connection, so no reply is lost and the shutdown is clean from both sides. Modern clients usually just close the socket, and pooled connections should be returned to the pool rather than closed, so `QUIT` is mostly useful in scripts and interactive sessions. + +## Syntax + +```redis +QUIT +``` + +## Arguments + +This command takes no arguments. + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +QUIT +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.quit(); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.sendCommand(["QUIT"]); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.quit() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Quit(context.Background()).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; +import java.nio.charset.StandardCharsets; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.commands.ProtocolCommand; + +ProtocolCommand command = () -> "QUIT".getBytes(StandardCharsets.UTF_8); +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.sendCommand(command); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("QUIT"); + + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# RESET +Source: https://upstash.com/docs/redis/commands/connection/reset + +Use `RESET` to return the connection to the state it had right after connecting. + +It discards an open [`MULTI`](/docs/redis/commands/transactions/multi) block, unwatches every key watched with [`WATCH`](/docs/redis/commands/transactions/watch), leaves subscriber and monitor modes, clears the connection name, re-enables replies, and de-authenticates the connection when the database requires a password. This makes it the safe way to hand a connection back to a pool after an error, since the next user cannot inherit a half-finished transaction or a leftover subscription. + +## Syntax + +```redis +RESET +``` + +## Arguments + +This command takes no arguments. + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `RESET` | +| RESP3 | Simple string `RESET` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +RESET +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.reset(); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.sendCommand(["RESET"]); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.reset() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Do(context.Background(), "RESET").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.reset(); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("RESET"); + + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# SELECT +Source: https://upstash.com/docs/redis/commands/connection/select + +Use `SELECT` to switch the connection to another database index. + +Upstash exposes a single logical database, so `0` is the only valid index and anything else returns an error. The command is accepted so that clients and frameworks that issue `SELECT 0` while setting up a connection keep working unchanged. To separate concerns inside one database, use key prefixes instead of numbered databases. + +## Syntax + +```redis +SELECT 0 +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `0` | Yes | No | Database index. Upstash supports only database 0. | + +## Important points + +* Upstash exposes a single logical database. Any index other than `0` returns an error. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +SELECT 0 +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.select("0"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.sendCommand(["SELECT", "0"]); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.select("0") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Do(context.Background(), "SELECT", "0").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.select(0); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("SELECT"); + command.arg("0"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# FCALL +Source: https://upstash.com/docs/redis/commands/functions/fcall + +Use `FCALL` to invoke a function from a library loaded with [`FUNCTION LOAD`](/docs/redis/commands/functions/function-load). + +`` tells the server how many of the arguments that follow are key names. Those keys reach the function in `KEYS` and every remaining argument in `ARGV`. Passing key names as keys instead of hardcoding them in the function body matters, because Redis uses that list for routing and access checks. + +The function runs on the server as a single atomic step, so a sequence of reads and writes that would otherwise need several round trips and a transaction becomes one command. Use [`FCALL_RO`](/docs/redis/commands/functions/fcall-ro) when the function only reads. Functions are the successor to [`EVAL`](/docs/redis/commands/scripting/eval) scripts: they are named, registered once as part of a library, and persisted with the dataset instead of being sent or looked up by digest on every call. + +Upstash runs a function under the global lock by default, since the engine cannot know in advance which keys it will touch. Registering the function with the `allow-key-locking` flag makes the call lock only the keys passed in the key list, so calls that work on disjoint keys run in parallel: + +```lua +redis.register_function{ + function_name='incr_quota', + callback=incr_quota, + flags={'allow-key-locking'} +} +``` + +Unlike Lua scripts, where the flag goes on the library shebang, this flag is set per registered function. With it set, every key the function touches must be passed as a key in the `FCALL` call: keys sent as ordinary arguments are not locked, and commands that need database-wide access, such as `FLUSHDB`, are rejected. See [Key-Based Locking](/docs/redis/features/key-locking) for the full rules. + + + Pass every key the function touches in the key list, even when it runs under + the global lock. Upstash keeps idle entries + [on disk](/docs/redis/features/durability): keys given in the key list are loaded + before the function starts and the lock is released during that read, but a + key that the function builds from `ARGV` while it runs is read from disk with + the lock held, stalling every command waiting on it. See + [Dynamic Keys and Latency](/docs/redis/features/key-locking#dynamic-keys-and-latency). + + +## Syntax + +```redis +FCALL [ [ ...]] [ [ ...]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Name of the registered function to call. | +| `` | Yes | No | Number of key arguments that follow. | +| `` | No | Yes | Redis key targeted by the command. | +| `` | No | Yes | Additional argument passed to the function. | + +## Important points + +* `numkeys` must equal the number of key arguments that immediately follow it; remaining arguments are available to the script or function as ordinary arguments. +* The function takes the global lock unless it was registered with the `allow-key-locking` flag, in which case only the keys passed in the key list are locked. See [Key-Based Locking](/docs/redis/features/key-locking). +* Pass every key the function touches in the key list whether or not `allow-key-locking` is set. A key built inside the function is read from disk under the lock when it is not in memory, and it is rejected outright when the flag is set. See [Dynamic Keys and Latency](/docs/redis/features/key-locking#dynamic-keys-and-latency). + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Reply returned by the invoked function | +| RESP3 | Reply returned by the invoked function | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +FCALL my_function 1 my-key value +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const code = ` +#!lua name=mylib +redis.register_function('helloworld', + function() + return 'Hello World!' + end +) +`; + +await redis.functions.load({ code, replace: true }); + +const res = await redis.functions.call("helloworld"); +console.log(res); // "Hello World!" +``` + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.fcall("my_function", "1", "my-key", "value"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.fCall("my_function", { keys: ["my-key"], arguments: ["value"] }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.fcall("my_function", 1, "my-key", "value") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.FCall(context.Background(), "my_function", []string{"my-key"}, "value").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.fcall("my_function", java.util.List.of("my-key"), java.util.List.of("value")); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("FCALL"); + command.arg("my_function"); + command.arg("1"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# FCALL_RO +Source: https://upstash.com/docs/redis/commands/functions/fcall-ro + +Use `FCALL_RO` to invoke a function that is declared read-only. + +The function must have been registered with the `no-writes` flag; calling a function without it returns an error. In exchange the server knows the call cannot modify data, so it can serve it on replicas and reject accidental writes outright. + +Apart from that restriction it behaves like [`FCALL`](/docs/redis/commands/functions/fcall): `` splits the arguments into the keys the function receives in `KEYS` and the plain arguments it receives in `ARGV`. + +Being read-only does not by itself make the call concurrent with others. The function takes the global lock unless it was also registered with the `allow-key-locking` flag, as in `flags={'no-writes', 'allow-key-locking'}`. With both flags, the call takes shared read locks on the keys passed in the key list, so several readers of the same key proceed together. See [Key-Based Locking](/docs/redis/features/key-locking). + +## Syntax + +```redis +FCALL_RO [ [ ...]] [ [ ...]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Name of the registered function to call. | +| `` | Yes | No | Number of key arguments that follow. | +| `` | No | Yes | Redis key targeted by the command. | +| `` | No | Yes | Additional argument passed to the function. | + +## Important points + +* `numkeys` must equal the number of key arguments that immediately follow it; remaining arguments are available to the script or function as ordinary arguments. +* A `no-writes` function still takes the global lock unless it was also registered with the `allow-key-locking` flag. See [Key-Based Locking](/docs/redis/features/key-locking). +* Pass every key the function reads in the key list whether or not `allow-key-locking` is set. A key built inside the function is read from disk under the lock when it is not in memory, and it is rejected outright when the flag is set. See [Dynamic Keys and Latency](/docs/redis/features/key-locking#dynamic-keys-and-latency). + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Reply returned by the invoked read-only function | +| RESP3 | Reply returned by the invoked read-only function | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +FCALL_RO my_function 1 my-key value +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const code = ` +#!lua name=ro_lib + +local function get_value(keys, args) + return redis.call('GET', keys[1]) +end + +redis.register_function({ + function_name='get_value', + callback=get_value, + flags={ 'no-writes' } +}) +`; + +await redis.functions.load({ code, replace: true }); + +// Call the read-only function +// Note: We can modify the keys usage here, but since it represents a read-only operation +// and we marked it with 'no-writes', it is safe to use callRo. +const value = await redis.functions.callRo("get_value", ["mykey"]) +``` + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.fcall_ro("my_function", "1", "my-key", "value"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.fCallRo("my_function", { keys: ["my-key"], arguments: ["value"] }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.fcall_ro("my_function", 1, "my-key", "value") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.FCallRO(context.Background(), "my_function", []string{"my-key"}, "value").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.fcallReadonly("my_function", java.util.List.of("my-key"), java.util.List.of("value")); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("FCALL_RO"); + command.arg("my_function"); + command.arg("1"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# FUNCTION DELETE +Source: https://upstash.com/docs/redis/commands/functions/function-delete + +Use `FUNCTION DELETE` to remove a function library and every function it registered. + +The argument is the library name declared when the library was loaded, not the name of a single function, and there is no way to delete one function from a library: reload the library with `REPLACE` instead. Deleting a library that does not exist returns an error, and calls to its functions fail until the library is loaded again. + +## Syntax + +```redis +FUNCTION DELETE +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Name of the function library. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +FUNCTION DELETE mylib +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.functions.delete("mylib") +``` + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.function("DELETE", "library-name"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.functionDelete("library-name"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.function_delete("library-name") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.FunctionDelete(context.Background(), "library-name").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.functionDelete("library-name"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("FUNCTION"); + command.arg("DELETE"); + command.arg("library-name"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# FUNCTION FLUSH +Source: https://upstash.com/docs/redis/commands/functions/function-flush + +Use `FUNCTION FLUSH` to remove every function library from the database. + +This wipes all registered libraries and functions at once and cannot be undone, so it belongs in test setup and provisioning tooling rather than application code. `ASYNC` reclaims the memory in the background and `SYNC` reclaims it before the reply is sent. + +## Syntax + +```redis +FUNCTION FLUSH [ASYNC | SYNC] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `(ASYNC \| SYNC)` | No | No | Choose one form: `ASYNC` (request asynchronous cleanup); `SYNC` (request synchronous cleanup). | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +FUNCTION FLUSH +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.functions.flush() +``` + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.function("FLUSH"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.functionFlush(); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.function_flush() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.FunctionFlush(context.Background()).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.functionFlush(); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("FUNCTION"); + command.arg("FLUSH"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# FUNCTION KILL +Source: https://upstash.com/docs/redis/commands/functions/function-kill + +Use `FUNCTION KILL` to stop a function that is currently running and has not yet written anything. + +A function that has already modified data cannot be killed, because stopping it halfway would leave the dataset in a state that no atomic step could produce. Check [`FUNCTION STATS`](/docs/redis/commands/functions/function-stats) to see whether a function is running before calling this. + +The current Upstash deployment recognizes the command but has no interruptible running-function state to act on, so it replies with a `NOTBUSY` error. + +## Syntax + +```redis +FUNCTION KILL +``` + +## Arguments + +This command takes no arguments. + +## Important points + +* The current deployment recognizes this command but reports `NOTBUSY` because it does not expose an interruptible running-function state. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Error reply (`NOTBUSY` on the current deployment) | +| RESP3 | Error reply (`NOTBUSY` on the current deployment) | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +FUNCTION KILL +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.function("KILL"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.functionKill(); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.function_kill() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.FunctionKill(context.Background()).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.functionKill(); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("FUNCTION"); + command.arg("KILL"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# FUNCTION LIST +Source: https://upstash.com/docs/redis/commands/functions/function-list + +Use `FUNCTION LIST` to inspect the function libraries loaded in the database. + +The reply describes each library with its name, the engine it runs on, and the functions it registers, including each function's description and flags such as `no-writes` and [`allow-key-locking`](/docs/redis/features/key-locking), which is the way to check whether a deployed function locks only its keys or the whole database. `LIBRARYNAME` filters the reply to library names matching a pattern, and `WITHCODE` includes the full source of each library, which is how you recover the code of a library that is deployed but no longer at hand. + +## Syntax + +```redis +FUNCTION LIST [LIBRARYNAME ] [WITHCODE] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `LIBRARYNAME ` | No | No | Return only libraries whose name matches this pattern. | +| `WITHCODE` | No | No | Include each library's source code. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of flat arrays containing library metadata | +| RESP3 | Array of maps containing library metadata | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +FUNCTION LIST +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const libs = await redis.functions.list({ + libraryName: "mylib", + withCode: true +}) + +console.log(libs) +// [ +// { +// libraryName: "mylib", +// engine: "LUA", +// functions: [{ +// name: "my_func", +// description: null, +// flags: [ "no-writes" ] +// }], +// libraryCode: "#!lua name=mylib ..." +// } +// ] +``` + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.function("LIST"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.functionList(); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.function_list() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.FunctionList(context.Background(), redis.FunctionListQuery{}).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.functionList(); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("FUNCTION"); + command.arg("LIST"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# FUNCTION LOAD +Source: https://upstash.com/docs/redis/commands/functions/function-load + +Use `FUNCTION LOAD` to register a library of functions in the database. + +The payload is the library source code. It must begin with a shebang line naming the engine and the library, such as `#!lua name=mylib`, and register each function with `redis.register_function`, giving it a name, a callback, and optional flags such as `no-writes`. The reply is the library name. + +`allow-key-locking` is one of those flags. It opts a function out of the global lock so that a call locks only the keys passed in its key list, which lets calls on disjoint keys run in parallel. Unlike Lua scripts, where the flag goes on the shebang line, it is declared per function in `redis.register_function`, and it is fixed until the library is loaded again. See [Key-Based Locking](/docs/redis/features/key-locking). + +Whether or not you set that flag, write functions so that every key they touch arrives in the key list rather than being assembled from `ARGV` inside the function, since an undeclared key can force a disk read while the lock is held. See [Dynamic Keys and Latency](/docs/redis/features/key-locking#dynamic-keys-and-latency). + +Loading fails when the library name is already in use unless `REPLACE` is given, which is how you deploy a new version of a library. Once loaded, functions are called by name with [`FCALL`](/docs/redis/commands/functions/fcall) or [`FCALL_RO`](/docs/redis/commands/functions/fcall-ro). Unlike scripts cached by [`SCRIPT LOAD`](/docs/redis/commands/scripting/script-load), libraries are part of the dataset, so they survive restarts and do not need to be re-sent by clients. + +## Syntax + +```redis +FUNCTION LOAD [REPLACE] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `REPLACE` | No | No | Allow replacement of an existing destination. | +| `` | Yes | No | Library source, including its `#!lua name=` shebang. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string | +| RESP3 | Bulk string | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +FUNCTION LOAD "#!lua name=mylib\nredis.register_function('helloworld', function() return 'Hello World!' end)" +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const code = `#!lua name=mylib + + -- Simple function that returns a string + redis.register_function( + 'helloworld', + function() return 'Hello World!' end + ) + + -- Complex function that modifies data with logic + local function my_hset(keys, args) + local hash = keys[1] + local time = redis.call('TIME')[1] + return redis.call('HSET', hash, '_last_modified_', time, unpack(args)) + end + + redis.register_function('my_hset', my_hset) +`; + +const libraryName = await redis.functions.load({ code, replace: true }); + +console.log(libraryName); // "mylib" +``` + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.function("LOAD", "function-code"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.functionLoad("function-code"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.function_load("function-code") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.FunctionLoad(context.Background(), "function-code").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.functionLoad("function-code"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("FUNCTION"); + command.arg("LOAD"); + command.arg("function-code"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# FUNCTION STATS +Source: https://upstash.com/docs/redis/commands/functions/function-stats + +Use `FUNCTION STATS` to read the current state of the function engine. + +The reply reports the function that is running right now, if any, together with how long it has been running and the command that started it, plus per-engine counts of loaded libraries and functions. It is the usual way to check whether a long-running function is in progress before deciding to call [`FUNCTION KILL`](/docs/redis/commands/functions/function-kill). + +## Syntax + +```redis +FUNCTION STATS +``` + +## Arguments + +This command takes no arguments. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Flat array of alternating keys and values | +| RESP3 | Map | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +FUNCTION STATS +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const stats = await redis.functions.stats() + +console.log(stats) +// { +// engines: { +// LUA: { +// librariesCount: 3, +// functionsCount: 15 +// } +// } +// } +``` + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.function("STATS"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.functionStats(); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.function_stats() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.FunctionStats(context.Background()).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.functionStats(); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("FUNCTION"); + command.arg("STATS"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# Functions commands +Source: https://upstash.com/docs/redis/commands/functions/overview + + +Call a function +Call a read-only function +Delete a library +Delete all libraries +Kill a running function +List all libraries +Load a library +Get function execution stats + + +# COPY +Source: https://upstash.com/docs/redis/commands/generic/copy + +Use `COPY` to copy the value stored at one key to another key. + +The destination gets an independent deep copy of the value, so later changes to either key do not affect the other, and the source key's remaining time to live is copied along with it. Any type can be copied. + +By default the command does nothing and returns `0` when the destination key already exists; `REPLACE` overwrites it instead. `DB` selects the destination database index, which on Upstash is always `0`. + +## Syntax + +```redis +COPY [DB ] [REPLACE] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key used as source. | +| `` | Yes | No | Redis key used as destination. | +| `DB ` | No | No | Index of the database to copy the key into. | +| `REPLACE` | No | No | Allow replacement of an existing destination. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: `1` if the key was copied, `0` otherwise | +| RESP3 | Integer: `1` if the key was copied, `0` otherwise | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +COPY source-key destination-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.copy("source-key", "destination-key"); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.copy("source-key", "destination-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.copy("source-key", "destination-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.copy("source-key", "destination-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.copy("source-key", "destination-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Copy(context.Background(), "source-key", "destination-key", 0, false).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.copy("source-key", "destination-key", false); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.copy("source-key", "destination-key", redis::CopyOptions::default())?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# DEL +Source: https://upstash.com/docs/redis/commands/generic/del + +Use `DEL` to delete one or more keys and the values they hold, whatever their type. + +The reply counts only the keys that actually existed, so deleting a key that is already gone is not an error and the count tells you how many were really removed. The memory is freed as part of the command, which for very large collections can take noticeable time; [`UNLINK`](/docs/redis/commands/generic/unlink) removes the keys just as immediately but frees their memory in the background. + +## Syntax + +```redis +DEL [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | Yes | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +DEL my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.del("key1", "key2"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.delete("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.del("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.del("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.delete("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Del(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.del("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.del("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# DUMP +Source: https://upstash.com/docs/redis/commands/generic/dump + +Use `DUMP` to serialize the value stored at a key into a portable, Redis-specific binary blob. + +The blob carries the value together with a version stamp and a checksum, but not the key name and not its time to live. Feeding it to [`RESTORE`](/docs/redis/commands/generic/restore) recreates the value under any key name, in the same database or in another one, which makes the pair the standard way to move or back up individual keys. A missing key returns null. + +The reply is raw binary data, not text: keep it in a byte-safe container and avoid string encodings that would corrupt it. + +## Syntax + +```redis +DUMP +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string or Null bulk string or null array | +| RESP3 | Bulk string or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +DUMP my-key +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.dump("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.dump("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.dump("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Dump(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.dump("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("DUMP"); + command.arg("my-key"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# EXISTS +Source: https://upstash.com/docs/redis/commands/generic/exists + +Use `EXISTS` to check whether one or more keys exist. + +The reply is the number of the given keys that exist, so with a single key it is simply `1` or `0`. A key listed several times is counted each time it is present, which means `EXISTS k k` returns `2` when `k` exists. Checking existence never transfers the value, so it stays cheap even for large values. + +## Syntax + +```redis +EXISTS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | Yes | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +EXISTS my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.set("key1", "value1") +await redis.set("key2", "value2") +const keys = await redis.exists("key1", "key2", "key3"); +console.log(keys) // 2 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.exists("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.exists("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.exists("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.exists("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Exists(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.exists("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.exists("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# EXPIRE +Source: https://upstash.com/docs/redis/commands/generic/expire + +Use `EXPIRE` to give a key a lifetime in seconds, after which the key is deleted automatically. + +Whether the expiration survives later writes depends on the command: replacing the value with [`SET`](/docs/redis/commands/string/set) clears it, while commands that modify a value in place, such as [`INCR`](/docs/redis/commands/string/incr), [`LPUSH`](/docs/redis/commands/list/lpush) or [`HSET`](/docs/redis/commands/hash/hset), leave it untouched. A negative lifetime deletes the key immediately. + +The optional condition decides when the new expiration is applied: `NX` only when the key currently has none, `XX` only when it already has one, `GT` only when the new expiration is later than the current one, and `LT` only when it is earlier. Since a key without an expiration counts as living forever, `GT` never adds one and `LT` always does. The reply is `1` when the expiration was set and `0` when the key does not exist or the condition was not met. + +Read the remaining lifetime with [`TTL`](/docs/redis/commands/generic/ttl) and remove it again with [`PERSIST`](/docs/redis/commands/generic/persist). + +## Syntax + +```redis +EXPIRE [NX | XX | GT | LT] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Lifetime in seconds. | +| `(NX \| XX \| GT \| LT)` | No | No | Choose one form: `NX` (only when the key has no expiration); `XX` (only when the key already has one); `GT` (only when the new expiration is later than the current one); `LT` (only when it is earlier). | + +## Important points + +* `NX` cannot be combined with `XX`, `GT`, or `LT`, and `GT` and `LT` cannot be used together. +* A key with no expiration counts as an infinite one, so `GT` never sets an expiration on such a key and `LT` always does. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: `1` if the timeout was set, `0` otherwise | +| RESP3 | Integer: `1` if the timeout was set, `0` otherwise | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +EXPIRE my-key 1000 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.set("mykey", "Hello"); +await redis.expire("mykey", 10); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.expire("my-key", 1000) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.expire("my-key", "1000"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.expire("my-key", 1000); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.expire("my-key", 1000) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Expire(context.Background(), "my-key", 1000*time.Second).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.expire("my-key", 1000); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.expire("my-key", 1000)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# EXPIREAT +Source: https://upstash.com/docs/redis/commands/generic/expireat + +Use `EXPIREAT` to schedule a key for automatic deletion at a fixed point in time, given as a Unix timestamp in seconds. + +It behaves exactly like [`EXPIRE`](/docs/redis/commands/generic/expire) except that the deadline is absolute rather than relative, which is what you want when several keys must expire at the same moment, such as the end of an hour or of a billing period. Computing the deadline once and reusing it also avoids the drift that repeated relative expirations introduce. A timestamp in the past deletes the key right away. + +The optional condition works as it does for `EXPIRE`: `NX` only when the key has no expiration, `XX` only when it already has one, `GT` only when the new deadline is later than the current one, and `LT` only when it is earlier. + +## Syntax + +```redis +EXPIREAT [NX | XX | GT | LT] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Expiration time as a Unix timestamp in seconds. | +| `(NX \| XX \| GT \| LT)` | No | No | Choose one form: `NX` (only when the key has no expiration); `XX` (only when the key already has one); `GT` (only when the new expiration is later than the current one); `LT` (only when it is earlier). | + +## Important points + +* `NX` cannot be combined with `XX`, `GT`, or `LT`, and `GT` and `LT` cannot be used together. +* A key with no expiration counts as an infinite one, so `GT` never sets an expiration on such a key and `LT` always does. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: `1` if the timeout was set, `0` otherwise | +| RESP3 | Integer: `1` if the timeout was set, `0` otherwise | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +EXPIREAT my-key 1735689600 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.set("mykey", "Hello"); +const tenSecondsFromNow = Math.floor(Date.now() / 1000) + 10; +await redis.expireat("mykey", tenSecondsFromNow); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.expireat("my-key", 1735689600) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.expireat("my-key", "1735689600"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.expireAt("my-key", 1735689600); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.expireat("my-key", 1735689600) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.ExpireAt(context.Background(), "my-key", time.Unix(1735689600, 0)).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.expireAt("my-key", 1735689600); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.expire_at("my-key", 1735689600)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# EXPIRETIME +Source: https://upstash.com/docs/redis/commands/generic/expiretime + +Use `EXPIRETIME` to read the absolute time at which a key will expire, as a Unix timestamp in seconds. + +The reply is `-1` when the key exists but has no expiration, and `-2` when the key does not exist, so the two cases can be told apart. Use [`TTL`](/docs/redis/commands/generic/ttl) when you need the remaining lifetime instead of the deadline, and [`PEXPIRETIME`](/docs/redis/commands/generic/pexpiretime) when you need millisecond precision. + +## Syntax + +```redis +EXPIRETIME +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | + +## Important points + +* Negative integer replies are sentinel values, not durations or timestamps; see the response description for missing or persistent data. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: expiration Unix time in seconds, `-1` if the key has no expiration, `-2` if the key does not exist | +| RESP3 | Integer: expiration Unix time in seconds, `-1` if the key has no expiration, `-2` if the key does not exist | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +EXPIRETIME my-key +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.expiretime("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.expireTime("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.expiretime("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.ExpireTime(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.expireTime("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.expire_time("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# KEYS +Source: https://upstash.com/docs/redis/commands/generic/keys + +Use `KEYS` to list every key in the database whose name matches a glob-style pattern. + +The pattern supports `*` for any sequence of characters, `?` for a single character, `[...]` for character classes, and `\` to escape a literal, so `user:*:session` matches all session keys of all users and `*` matches everything. + +The command walks the entire keyspace and returns all matches in one reply, which on a database of any real size means a long block and a very large response. Treat it as a debugging and maintenance tool: on hot paths use [`SCAN`](/docs/redis/commands/generic/scan), which accepts the same `MATCH` patterns but walks the keyspace in small batches, or keep an index of your keys in a set instead. + +## Syntax + +```redis +KEYS +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Glob-style pattern to match keys against. | + +## Important points + +* This command can expose administrative information or make a broad destructive change. Restrict it to trusted code paths. +* This operation can inspect a large part of the database. Prefer cursor-based scans where possible and avoid unbounded use on hot paths. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string keys | +| RESP3 | Array of bulk-string keys | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +KEYS * +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const keys = await redis.keys("prefix*"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.keys("*") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.keys("*"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.keys("*"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.keys("*") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Keys(context.Background(), "*").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.keys("*"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.keys("*")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# MEMORY USAGE +Source: https://upstash.com/docs/redis/commands/generic/memory-usage + +Use `MEMORY USAGE` to estimate how many bytes a key and its value occupy in memory. + +The figure covers the stored data along with its internal overhead, so it is larger than the raw size of the value and is meant for comparing keys rather than for exact accounting. For aggregate types such as hashes, lists, sets, sorted sets, and streams the value is sampled instead of fully traversed: `SAMPLES` sets how many nested elements are inspected, and the value is clamped to the range this deployment supports, so it tunes the estimate rather than forcing an exact traversal. A missing key returns null. + +It is the usual way to find out which keys are responsible for memory growth before deciding what to trim or restructure. + +## Syntax + +```redis +MEMORY USAGE [SAMPLES ] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | Key whose in-memory footprint should be estimated. | +| `SAMPLES count` | No | No | Sampling count used when estimating large stream values. | + +## Important points + +* The result is an estimate in bytes and can change as the internal representation changes. +* A missing key returns null. The sampling count is clamped to the deployment's supported range. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer or Null bulk string or null array | +| RESP3 | Integer or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +MEMORY USAGE my-key SAMPLES 10 +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.memory("USAGE", "my-key", "SAMPLES", "10"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.memoryUsage("my-key", { SAMPLES: 10 }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.memory_usage("my-key", samples=10) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.MemoryUsage(context.Background(), "my-key", 10).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.memoryUsage("my-key", 10); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("MEMORY"); + command.arg("USAGE"); + command.arg("my-key"); + command.arg("SAMPLES"); + command.arg("10"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# Generic commands +Source: https://upstash.com/docs/redis/commands/generic/overview + + +Copy a key to another key +Delete one or more keys +Serialize a key's value +Check if keys exist +Set a key's TTL in seconds +Set expiry as Unix timestamp +Get expiry as Unix timestamp +Find keys matching a pattern +Estimate memory used by a key +Remove the expiration from a key +Set a key's TTL in milliseconds +Set expiry as Unix ms timestamp +Get expiry as Unix ms timestamp +Get TTL in milliseconds +Return a random key +Rename a key +Rename a key if new key doesn't exist +Deserialize and restore a key +Incrementally iterate keys +Update last access time of keys +Get TTL in seconds +Get the type of a key +Delete keys asynchronously +Wait for replica acknowledgements +Wait for local and replica persistence + + +# PERSIST +Source: https://upstash.com/docs/redis/commands/generic/persist + +Use `PERSIST` to remove the expiration from a key so that it stops being deleted automatically and lives until it is removed explicitly. + +The reply is `1` when an expiration was removed and `0` when the key does not exist or had no expiration to begin with. This is how a value gets promoted from temporary to permanent without rewriting it, for example when a trial record becomes a persistent one. + +## Syntax + +```redis +PERSIST +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: `1` if the timeout was removed, `0` otherwise | +| RESP3 | Integer: `1` if the timeout was removed, `0` otherwise | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PERSIST my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.persist(key); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.persist("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.persist("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.persist("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.persist("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Persist(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.persist("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.persist("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# PEXPIRE +Source: https://upstash.com/docs/redis/commands/generic/pexpire + +Use `PEXPIRE` to give a key a lifetime in milliseconds, after which the key is deleted automatically. + +It is the millisecond form of [`EXPIRE`](/docs/redis/commands/generic/expire) and behaves identically otherwise: replacing the value with [`SET`](/docs/redis/commands/string/set) clears the expiration, while in-place updates keep it, and a negative lifetime deletes the key immediately. The sub-second precision matters for short-lived keys such as locks and rate limit windows. + +The optional condition decides when the new expiration is applied: `NX` only when the key has none, `XX` only when it already has one, `GT` only when the new expiration is later than the current one, and `LT` only when it is earlier. + +## Syntax + +```redis +PEXPIRE [NX | XX | GT | LT] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Lifetime in milliseconds. | +| `(NX \| XX \| GT \| LT)` | No | No | Choose one form: `NX` (only when the key has no expiration); `XX` (only when the key already has one); `GT` (only when the new expiration is later than the current one); `LT` (only when it is earlier). | + +## Important points + +* `NX` cannot be combined with `XX`, `GT`, or `LT`, and `GT` and `LT` cannot be used together. +* A key with no expiration counts as an infinite one, so `GT` never sets an expiration on such a key and `LT` always does. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: `1` if the timeout was set, `0` otherwise | +| RESP3 | Integer: `1` if the timeout was set, `0` otherwise | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PEXPIRE my-key 1000 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.pexpire(key, 60_000); // 1 minute +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.pexpire("my-key", 1000) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.pexpire("my-key", "1000"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.pExpire("my-key", 1000); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.pexpire("my-key", 1000) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.PExpire(context.Background(), "my-key", time.Second).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.pexpire("my-key", 1000); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.pexpire("my-key", 1000)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# PEXPIREAT +Source: https://upstash.com/docs/redis/commands/generic/pexpireat + +Use `PEXPIREAT` to schedule a key for automatic deletion at a fixed point in time, given as a Unix timestamp in milliseconds. + +It combines the absolute deadline of [`EXPIREAT`](/docs/redis/commands/generic/expireat) with the millisecond precision of [`PEXPIRE`](/docs/redis/commands/generic/pexpire), which is what you need when many keys must expire at exactly the same instant. A timestamp in the past deletes the key right away. + +The optional condition works as elsewhere: `NX` only when the key has no expiration, `XX` only when it already has one, `GT` only when the new deadline is later than the current one, and `LT` only when it is earlier. + +## Syntax + +```redis +PEXPIREAT [NX | XX | GT | LT] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Expiration time as a Unix timestamp in milliseconds. | +| `(NX \| XX \| GT \| LT)` | No | No | Choose one form: `NX` (only when the key has no expiration); `XX` (only when the key already has one); `GT` (only when the new expiration is later than the current one); `LT` (only when it is earlier). | + +## Important points + +* `NX` cannot be combined with `XX`, `GT`, or `LT`, and `GT` and `LT` cannot be used together. +* A key with no expiration counts as an infinite one, so `GT` never sets an expiration on such a key and `LT` always does. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: `1` if the timeout was set, `0` otherwise | +| RESP3 | Integer: `1` if the timeout was set, `0` otherwise | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PEXPIREAT my-key 1735689600 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.set("mykey", "Hello"); +const tenMinutesFromNow = Date.now() + 10 * 60 * 1000; +await redis.pexpireat("mykey", tenMinutesFromNow); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.pexpireat("my-key", 1735689600) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.pexpireat("my-key", "1735689600"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.pExpireAt("my-key", 1735689600); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.pexpireat("my-key", 1735689600) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.PExpireAt(context.Background(), "my-key", time.UnixMilli(1735689600)).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.pexpireAt("my-key", 1735689600); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.pexpire_at("my-key", 1735689600)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# PEXPIRETIME +Source: https://upstash.com/docs/redis/commands/generic/pexpiretime + +Use `PEXPIRETIME` to read the absolute time at which a key will expire, as a Unix timestamp in milliseconds. + +The reply is `-1` when the key exists but has no expiration and `-2` when the key does not exist. It is the millisecond form of [`EXPIRETIME`](/docs/redis/commands/generic/expiretime), and it reports a deadline rather than a remaining lifetime, which makes it the value to compare against a clock when you need to know exactly when something is due. + +## Syntax + +```redis +PEXPIRETIME +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | + +## Important points + +* Negative integer replies are sentinel values, not durations or timestamps; see the response description for missing or persistent data. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: expiration Unix time in milliseconds, `-1` if the key has no expiration, `-2` if the key does not exist | +| RESP3 | Integer: expiration Unix time in milliseconds, `-1` if the key has no expiration, `-2` if the key does not exist | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PEXPIRETIME my-key +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.pexpiretime("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.pExpireTime("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.pexpiretime("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.PExpireTime(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.pexpireTime("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.pexpire_time("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# PTTL +Source: https://upstash.com/docs/redis/commands/generic/pttl + +Use `PTTL` to read how much longer a key will live, in milliseconds. + +The reply is `-1` when the key exists but has no expiration and `-2` when the key does not exist, so a missing key and a permanent one are easy to tell apart. It is the millisecond form of [`TTL`](/docs/redis/commands/generic/ttl), and the extra precision matters for short-lived keys such as locks, where rounding to whole seconds hides most of the remaining lifetime. + +## Syntax + +```redis +PTTL +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | + +## Important points + +* Negative integer replies are sentinel values, not durations or timestamps; see the response description for missing or persistent data. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: remaining lifetime in milliseconds, `-1` if the key has no expiration, `-2` if the key does not exist | +| RESP3 | Integer: remaining lifetime in milliseconds, `-1` if the key has no expiration, `-2` if the key does not exist | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PTTL my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const millis = await redis.pttl(key); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.pttl("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.pttl("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.pTTL("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.pttl("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.PTTL(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.pttl("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.pttl("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# RANDOMKEY +Source: https://upstash.com/docs/redis/commands/generic/randomkey + +Use `RANDOMKEY` to get the name of a random key from the database without reading its value. + +The reply is null when the database is empty. Keys are picked by sampling the keyspace rather than by drawing uniformly from it, and nothing prevents the same key from coming up repeatedly, so treat it as a way to look at a sample of your data while debugging rather than as a way to iterate over it. Use [`SCAN`](/docs/redis/commands/generic/scan) when you need to cover every key. + +## Syntax + +```redis +RANDOMKEY +``` + +## Arguments + +This command takes no arguments. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Null bulk string or null array or Bulk string | +| RESP3 | Null or Bulk string | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +RANDOMKEY +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const key = await redis.randomkey(); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.randomkey() +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.randomkey(); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.randomKey(); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.randomkey() +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.RandomKey(context.Background()).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.randomKey(); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("RANDOMKEY"); + + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# RENAME +Source: https://upstash.com/docs/redis/commands/generic/rename + +Use `RENAME` to give an existing key a new name. + +The value moves with the key and so does its remaining time to live, and the operation is atomic, so no client ever sees both names or neither. If a key with the destination name already exists it is overwritten and its old value is deleted. Renaming a key that does not exist returns an error. + +Use [`RENAMENX`](/docs/redis/commands/generic/renamenx) when the destination must not be overwritten. A common pattern is to build a replacement value under a temporary key and then rename it over the live key, which swaps the data in one atomic step. + +## Syntax + +```redis +RENAME +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Redis key used as newkey. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +RENAME old-key new-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.rename("old", "new"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.rename("old-key", "new-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.rename("old-key", "new-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.rename("old-key", "new-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.rename("old-key", "new-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Rename(context.Background(), "old-key", "new-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.rename("old-key", "new-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.rename("old-key", "new-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# RENAMENX +Source: https://upstash.com/docs/redis/commands/generic/renamenx + +Use `RENAMENX` to rename a key only when the new name is not already in use. + +The reply is `1` when the rename happened and `0` when the destination already existed and nothing was changed; renaming a key that does not exist returns an error. Because the check and the rename are one atomic step, the command can serve as a way to claim a name: only one of several clients trying to rename onto the same destination succeeds. + +## Syntax + +```redis +RENAMENX +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Redis key used as newkey. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: `1` if the key was renamed, `0` if the destination already exists | +| RESP3 | Integer: `1` if the key was renamed, `0` if the destination already exists | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +RENAMENX old-key new-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const renamed = await redis.renamenx("old", "new"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.renamenx("old-key", "new-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.renamenx("old-key", "new-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.renameNX("old-key", "new-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.renamenx("old-key", "new-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.RenameNX(context.Background(), "old-key", "new-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.renamenx("old-key", "new-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.rename_nx("old-key", "new-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# RESTORE +Source: https://upstash.com/docs/redis/commands/generic/restore + +Use `RESTORE` to recreate a key from a payload produced by [`DUMP`](/docs/redis/commands/generic/dump). + +`` gives the new key a lifetime in milliseconds, where `0` means no expiration; with `ABSTTL` the same number is read as an absolute Unix timestamp in milliseconds instead. The command fails if the key already exists unless `REPLACE` is given. + +The payload's version stamp and checksum are verified before anything is written, so a truncated, corrupted, or foreign payload is rejected rather than loaded. `IDLETIME` and `FREQ` seed the eviction metadata of the new key so that a restored key does not automatically look freshly used. + +## Syntax + +```redis +RESTORE + [REPLACE] + [ABSTTL] + [IDLETIME ] + [FREQ ] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Lifetime in milliseconds; `0` restores the key without an expiration. | +| `` | Yes | No | Payload produced by `DUMP`. | +| `REPLACE` | No | No | Allow replacement of an existing destination. | +| `ABSTTL` | No | No | Treat `` as an absolute Unix timestamp in milliseconds. | +| `IDLETIME ` | No | No | Set the key's idle time, in seconds. | +| `FREQ ` | No | No | Set the key's access frequency counter. | + +## Important points + +* This command can expose administrative information or make a broad destructive change. Restrict it to trusted code paths. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +RESTORE my-key 1 serialized-value +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.restore("my-key", "1", "serialized-value"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.restore("my-key", 1, "serialized-value"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.restore("my-key", 1, "serialized-value") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Restore(context.Background(), "my-key", time.Millisecond, "serialized-value").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.restore("my-key", 1, "serialized-value".getBytes()); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("RESTORE"); + command.arg("my-key"); + command.arg("1"); + command.arg("serialized-value"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# SCAN +Source: https://upstash.com/docs/redis/commands/generic/scan + +Use `SCAN` to walk through the keys of the database incrementally, a batch at a time. + +Each call takes a cursor and returns the next cursor together with a batch of keys. Start with cursor `0` and keep calling with the cursor from the previous reply until the server returns `0` again, which marks the end of the iteration. Because the work is split over many short calls, `SCAN` never blocks the server the way [`KEYS`](/docs/redis/commands/generic/keys) can on a large keyspace. + +`MATCH` filters the returned keys with a glob-style pattern, `COUNT` hints at how much work each call should do (a hint about effort, not a page size, so batches vary in length), and `TYPE` limits the reply to keys of one type. Filtering is applied after a batch has been read, so a call can legitimately return no keys at all while the cursor is still non-zero: only the cursor tells you when the iteration is over. + +The guarantee is that every key present for the whole iteration is returned at least once. Keys added or removed while the scan runs may or may not show up, and a key can be returned more than once, so make the processing of each key idempotent. [`HSCAN`](/docs/redis/commands/hash/hscan), [`SSCAN`](/docs/redis/commands/set/sscan), and [`ZSCAN`](/docs/redis/commands/sorted-set/zscan) apply the same mechanism inside a single collection. + +## Syntax + +```redis +SCAN [MATCH ] [COUNT ] [TYPE ] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Cursor returned by the previous call; start at `0`. | +| `MATCH ` | No | No | Return only elements matching this glob-style pattern. | +| `COUNT ` | No | No | Hint for how much work each iteration should do. | +| `TYPE ` | No | No | Return only keys of this type, such as `string`, `list`, or `hash`. | + +## Important points + +* This operation can inspect a large part of the database. Prefer cursor-based scans where possible and avoid unbounded use on hot paths. +* The cursor is opaque. Start with `0` and continue until the server returns cursor `0`; a single iteration may return no elements. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Two-element array: cursor and array of bulk-string keys | +| RESP3 | Two-element array: cursor and array of bulk-string keys | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +SCAN 0 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const [cursor, keys] = await redis.scan(0, { match: "*" }); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.scan(0) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.scan("0"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.scan("0"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.scan(0) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, _, err := client.Scan(context.Background(), 0, "*", 0).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.scan("0"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let iter: redis::Iter = connection.scan()?; + for key in iter { + println!("{key}"); + } + Ok(()) +} +``` + + + + + +# TOUCH +Source: https://upstash.com/docs/redis/commands/generic/touch + +Use `TOUCH` to update the last access time of one or more keys without reading their values. + +The reply counts how many of the given keys exist, just like [`EXISTS`](/docs/redis/commands/generic/exists), but the call also refreshes the idle time and access frequency that the LRU and LFU eviction policies rely on. That makes it a way to tell the server that a key is still in use, for example to keep a cached value from being evicted while a slower process is still going to need it. It does not change the key's expiration. + +## Syntax + +```redis +TOUCH [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | Yes | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +TOUCH my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.touch("key1", "key2", "key3"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.touch("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.touch("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.touch("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.touch("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Touch(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.touch("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("TOUCH"); + command.arg("my-key"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# TTL +Source: https://upstash.com/docs/redis/commands/generic/ttl + +Use `TTL` to read how much longer a key will live, in seconds. + +The reply is `-1` when the key exists but has no expiration and `-2` when the key does not exist, so these two are never confused with a real remaining lifetime. Values are rounded to whole seconds; use [`PTTL`](/docs/redis/commands/generic/pttl) for millisecond precision and [`EXPIRETIME`](/docs/redis/commands/generic/expiretime) when you want the absolute deadline rather than the time left. + +## Syntax + +```redis +TTL +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | + +## Important points + +* Negative integer replies are sentinel values, not durations or timestamps; see the response description for missing or persistent data. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: remaining lifetime in seconds, `-1` if the key has no expiration, `-2` if the key does not exist | +| RESP3 | Integer: remaining lifetime in seconds, `-1` if the key has no expiration, `-2` if the key does not exist | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +TTL my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const seconds = await redis.ttl(key); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.ttl("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.ttl("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.ttl("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.ttl("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.TTL(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.ttl("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.ttl("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# TYPE +Source: https://upstash.com/docs/redis/commands/generic/type + +Use `TYPE` to find out which data type is stored at a key. + +The reply is one of `string`, `list`, `set`, `zset`, `hash`, or `stream`, and `none` when the key does not exist. It is the way to dispatch generic code over keys of mixed types, since applying a command to the wrong type fails with a `WRONGTYPE` error, and the way to inspect unfamiliar data before deciding how to read it. + +## Syntax + +```redis +TYPE +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string: the type name, or `none` if the key does not exist | +| RESP3 | Simple string: the type name, or `none` if the key does not exist | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +TYPE my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.set("key", "value"); +const t = await redis.type("key"); +console.log(t) // "string" +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.type("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.type("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.type("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.type("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Type(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.type("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.key_type("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# UNLINK +Source: https://upstash.com/docs/redis/commands/generic/unlink + +Use `UNLINK` to delete keys without freeing their memory in the foreground. + +The keys are removed from the keyspace immediately, so from a client's point of view they are gone as soon as the command returns, but the memory of large values is reclaimed by a background thread. That makes it a safer alternative to [`DEL`](/docs/redis/commands/generic/del) for collections with many elements, where freeing memory synchronously can block the server for a noticeable time. The reply counts the keys that existed. + +## Syntax + +```redis +UNLINK [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | Yes | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +UNLINK my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.unlink("key1", "key2"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.unlink("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.unlink("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.unlink("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.unlink("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Unlink(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.unlink("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.unlink("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# WAIT +Source: https://upstash.com/docs/redis/commands/generic/wait + +Use `WAIT` to block until preceding writes have been acknowledged by a number of replicas, or until a timeout expires. + +The reply is the number of replicas that acknowledged, which can be lower than `` when the timeout is reached, so callers must check it instead of assuming success. A timeout of `0` waits indefinitely. + +`WAIT` raises the durability you can observe for a write, which is useful right before an action that must not be undone by a failover, such as replying to a payment webhook. It does not make Redis strongly consistent: an acknowledged write can still be lost if the primary and the acknowledging replicas fail together. + +On Upstash the command waits for the writes enqueued before it began, including writes made by other connections, which is broader than the per-connection wording used by some Redis clients. + +## Syntax + +```redis +WAIT +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `numreplicas` | Yes | No | Non-negative number of replicas that should acknowledge prior writes on this connection. | +| `timeout` | Yes | No | Maximum wait in milliseconds; `0` means no timeout. | + +## Important points + +* This deployment waits for writes enqueued before `WAIT` begins, including writes from other connections. That is broader than the per-connection wording used by Redis clients. +* The reply can be lower than `numreplicas` when the timeout expires. This improves observed replication durability but does not make Redis a strongly consistent store. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +WAIT 1 1000 +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.wait("1", "1000"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.wait(1, 1000); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.wait("1", "1000") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Wait(context.Background(), 1, time.Second).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.waitReplicas(1, 1000); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("WAIT"); + command.arg("1"); + command.arg("1000"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# WAITAOF +Source: https://upstash.com/docs/redis/commands/generic/waitaof + +Use `WAITAOF` to block until preceding writes have been persisted to the append-only file locally and on replicas. + +`` is how many local acknowledgements to wait for and `` how many replicas must have persisted the writes. The two-element reply gives the local count first and the replica count second, and either can come back lower than requested when the timeout expires, so both need checking. A timeout of `0` waits indefinitely. + +Where [`WAIT`](/docs/redis/commands/generic/wait) confirms only that replicas received a write, `WAITAOF` confirms that it reached persistent storage, which is the stronger guarantee to ask for before acknowledging work that must survive a restart. On Upstash it waits for the writes enqueued before it began, including writes made by other connections. + +## Syntax + +```redis +WAITAOF +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `numlocal` | Yes | No | Whether to wait for local persistence: `0` or `1`. | +| `numreplicas` | Yes | No | Non-negative number of replicas whose append-only files should include prior writes. | +| `timeout` | Yes | No | Maximum wait in milliseconds; `0` means no timeout. | + +## Important points + +* This deployment waits for writes enqueued before `WAITAOF` begins, including writes from other connections. +* The two-element reply contains the local persistence acknowledgement first and the replica persistence count second. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Two-element array of integers: local and replica acknowledgments | +| RESP3 | Two-element array of integers: local and replica acknowledgments | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +WAITAOF 1 1 1000 +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("WAITAOF", "1", "1", "1000"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.sendCommand(["WAITAOF", "1", "1", "1000"]); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.waitaof("1", "1", "1000") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.WaitAOF(context.Background(), 1, 1, time.Second).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.waitAOF(1, 1, 1000); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("WAITAOF"); + command.arg("1"); + command.arg("1"); + command.arg("1000"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# GEOADD +Source: https://upstash.com/docs/redis/commands/geo/geoadd + +Use `GEOADD` to add longitude, latitude, and member triples to a geospatial index. + +Each position is encoded into a 52-bit geohash and stored as the score of the member in a sorted set, so a geospatial key is an ordinary sorted set and commands such as [`ZREM`](/docs/redis/commands/sorted-set/zrem), [`ZCARD`](/docs/redis/commands/sorted-set/zcard), and [`ZSCAN`](/docs/redis/commands/sorted-set/zscan) work on it. Longitude must be between -180 and 180 and latitude between -85.05112878 and 85.05112878; anything outside those bounds returns an error. Adding a member that is already present moves it to the new position, and the encoding means coordinates read back with [`GEOPOS`](/docs/redis/commands/geo/geopos) are very close to, but not exactly, the ones you stored. + +`NX` only adds members that are not there yet, `XX` only updates members that already exist, and `CH` makes the reply count every member that changed rather than only the ones that were added. + +## Syntax + +```redis +GEOADD + [NX | XX] + [CH] + + [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `(NX \| XX)` | No | No | Choose one form: `NX` (only add new members, never update an existing one); `XX` (only update members that already exist). | +| `CH` | No | No | Count changed members rather than only new members. | +| ` ` | Yes | Yes | Longitude, latitude, and the member they belong to. Repeat to add several members. | + +## Important points + +* `NX` and `XX` are mutually exclusive. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +GEOADD my-key 29.0 41.0 member +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.geoadd("my-key", { + longitude: 29.0, + latitude: 41.0, + member: "member", +}); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.geoadd("my-key", (29.0, 41.0, "member")) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.geoadd("my-key", "29.0", "41.0", "member"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.geoAdd("my-key", { longitude: 29, latitude: 41, member: "member" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.geoadd("my-key", (29.0, 41.0, "member")) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.GeoAdd(context.Background(), "my-key", &redis.GeoLocation{Longitude: 29.0, Latitude: 41.0, Name: "member"}).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.geoadd("my-key", 29.0, 41.0, "member"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.geo_add("my-key", (29.0, 41.0, "member"))?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# GEODIST +Source: https://upstash.com/docs/redis/commands/geo/geodist + +Use `GEODIST` to get the distance between two members of a geospatial index. + +The unit defaults to meters and can be set to `m`, `km`, `ft`, or `mi`. The distance is a great-circle distance computed from the stored positions assuming the Earth is a sphere, so it carries the small error of the geohash encoding and, of course, says nothing about the distance actually travelled on roads. If either member is missing from the index the reply is null. + +## Syntax + +```redis +GEODIST [m | km | ft | mi] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | First member. | +| `` | Yes | No | Second member. | +| `(m \| km \| ft \| mi)` | No | No | Distance unit: `m` (meters), `km` (kilometers), `ft` (feet), or `mi` (miles). Defaults to `m` when omitted. | + +## Important points + +* The distance is always returned as a bulk string, in both RESP2 and RESP3. Client libraries commonly decode it to a language number. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Null bulk string or null array or Bulk string | +| RESP3 | Null or Bulk string | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +GEODIST my-key member1 member2 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.geodist("my-key", "member1", "member2"); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.geodist("my-key", "member1", "member2") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.geodist("my-key", "member1", "member2"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.geoDist("my-key", "member1", "member2"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.geodist("my-key", "member1", "member2") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.GeoDist(context.Background(), "my-key", "member1", "member2", "m").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.geodist("my-key", "member1", "member2"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::geo::Unit; +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.geo_dist("my-key", "member1", "member2", Unit::Meters)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# GEOHASH +Source: https://upstash.com/docs/redis/commands/geo/geohash + +Use `GEOHASH` to get standard Geohash strings for members of a geospatial index. + +The reply holds one 11-character string per requested member, in the order requested, with null for members that are not in the index. These are the strings used by geohash.org and by other geospatial tools, which makes the command the right way to export positions or to share them with systems that speak Geohash. They are derived from the stored 52-bit position, so they reflect the same rounding as [`GEOPOS`](/docs/redis/commands/geo/geopos). + +## Syntax + +```redis +GEOHASH [ [ ...]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | No | Yes | Member name. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string geohashes or null values | +| RESP3 | Array of bulk-string geohashes or null values | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +GEOHASH my-key member +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.geohash("my-key", "member"); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.geohash("my-key", "member") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.geohash("my-key", "member"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.geoHash("my-key", "member"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.geohash("my-key", "member") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.GeoHash(context.Background(), "my-key", "member").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.geohash("my-key", "member"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.geo_hash("my-key", "member")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# GEOPOS +Source: https://upstash.com/docs/redis/commands/geo/geopos + +Use `GEOPOS` to get the longitude and latitude of members of a geospatial index. + +The reply holds one entry per requested member, in the order requested, each an array with longitude first and latitude second, and null for members that are not in the index. Positions are decoded from the stored geohash, so they are very close to but not bit-for-bit identical with the coordinates originally passed to [`GEOADD`](/docs/redis/commands/geo/geoadd). + +## Syntax + +```redis +GEOPOS [ [ ...]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | No | Yes | Member name. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of coordinate-pair arrays or null values | +| RESP3 | Array of coordinate-pair arrays or null values | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +GEOPOS my-key member +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.geopos("my-key", "member"); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.geopos("my-key", "member") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.geopos("my-key", "member"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.geoPos("my-key", "member"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.geopos("my-key", "member") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.GeoPos(context.Background(), "my-key", "member").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.geopos("my-key", "member"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.geo_pos("my-key", "member")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# GEORADIUS +Source: https://upstash.com/docs/redis/commands/geo/georadius + + + Prefer [`GEOSEARCH`](/docs/redis/commands/geo/geosearch) with `FROMLONLAT` and `BYRADIUS` in new code: `GEOSEARCH FROMLONLAT BYRADIUS (m | km | ft | mi)`. In place of `STORE` and `STOREDIST`, use [`GEOSEARCHSTORE`](/docs/redis/commands/geo/geosearchstore) with the same query. + + +Use `GEORADIUS` to find the members of a geospatial index that lie within a given radius of a longitude and latitude point. + +By default only member names are returned. `WITHDIST` adds each member's distance from the center in the unit of the query, `WITHCOORD` adds its coordinates, and `WITHHASH` adds its raw 52-bit geohash score. `COUNT` caps the number of results and, combined with `ANY`, lets the server stop as soon as it has enough matches instead of examining the whole area, which is faster but returns an arbitrary subset rather than the nearest ones. `ASC` and `DESC` sort the results by distance from the center. + +`STORE` writes the matching members into a sorted set scored by geohash, so the result stays usable as a geospatial index, while `STOREDIST` scores them by their distance from the center, which makes the result easy to page through by proximity. + +[`GEOSEARCH`](/docs/redis/commands/geo/geosearch) and [`GEOSEARCHSTORE`](/docs/redis/commands/geo/geosearchstore) do the same work and additionally support rectangular areas. Use [`GEORADIUS_RO`](/docs/redis/commands/geo/georadius-ro) if you want a form that cannot write. + +## Syntax + +```redis +GEORADIUS (m | km | ft | mi) + [WITHCOORD] + [WITHDIST] + [WITHHASH] + [COUNT [ANY]] + [ASC | DESC] + [STORE | STOREDIST ] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Longitude in degrees, from -180 to 180. | +| `` | Yes | No | Latitude in degrees, from -85.05112878 to 85.05112878. | +| `` | Yes | No | Search radius, in the unit given after it. | +| `(m \| km \| ft \| mi)` | Yes | No | Distance unit: `m` (meters), `km` (kilometers), `ft` (feet), or `mi` (miles). | +| `WITHCOORD` | No | No | Also return the longitude and latitude of each match. | +| `WITHDIST` | No | No | Also return the distance from the center, in the requested unit. | +| `WITHHASH` | No | No | Also return the raw 52-bit geohash score of each match. | +| `COUNT [ANY]` | No | No | Return at most `` matches. `ANY` returns as soon as enough matches are found, instead of sorting every match first. | +| `(ASC \| DESC)` | No | No | Sort the matches by distance from the center: `ASC` (nearest first) or `DESC` (farthest first). Unsorted when omitted. | +| `(STORE \| STOREDIST )` | No | No | Store the matches in a sorted set instead of returning them: `STORE` scores them by geohash, so the destination stays a geospatial index, and `STOREDIST` scores them by their distance from the center. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string members or member-detail arrays, or Integer when storing | +| RESP3 | Array of bulk-string members or member-detail arrays, or Integer when storing | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +GEORADIUS my-key 29.0 41.0 1.5 m +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.georadius("my-key", 29.0, 41.0, 1.5, "M") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.georadius("my-key", "29.0", "41.0", "1.5", "m"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.geoRadius("my-key", { longitude: 29, latitude: 41 }, 1.5, "m"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.georadius("my-key", 29.0, 41.0, 1.5, "m") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.GeoRadius(context.Background(), "my-key", 29.0, 41.0, &redis.GeoRadiusQuery{Radius: 1.5, Unit: "m"}).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.georadius("my-key", 29.0, 41.0, 1.5, redis.clients.jedis.args.GeoUnit.M); + System.out.println(result); +} +``` + + + + + +```rust +use redis::geo::{RadiusOptions, Unit}; +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.geo_radius( + "my-key", + 29.0, + 41.0, + 1.5, + Unit::Meters, + RadiusOptions::default(), + )?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# GEORADIUS_RO +Source: https://upstash.com/docs/redis/commands/geo/georadius-ro + + + Prefer [`GEOSEARCH`](/docs/redis/commands/geo/geosearch) with `FROMLONLAT` and `BYRADIUS` in new code: `GEOSEARCH FROMLONLAT BYRADIUS (m | km | ft | mi)`. + + +Use `GEORADIUS_RO` to find members within a radius of a point. It is the read-only form of [`GEORADIUS`](/docs/redis/commands/geo/georadius). + +It accepts the same query and the same `WITHCOORD`, `WITHDIST`, `WITHHASH`, `COUNT`, and sorting options, but it has no `STORE` or `STOREDIST` clause, so the server knows the call cannot write and can serve it on replicas and from read-only scripts. + +[`GEOSEARCH`](/docs/redis/commands/geo/geosearch) is read-only as well and also supports rectangular areas. + +## Syntax + +```redis +GEORADIUS_RO (m | km | ft | mi) + [WITHCOORD] + [WITHDIST] + [WITHHASH] + [COUNT [ANY]] + [ASC | DESC] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Longitude in degrees, from -180 to 180. | +| `` | Yes | No | Latitude in degrees, from -85.05112878 to 85.05112878. | +| `` | Yes | No | Search radius, in the unit given after it. | +| `(m \| km \| ft \| mi)` | Yes | No | Distance unit: `m` (meters), `km` (kilometers), `ft` (feet), or `mi` (miles). | +| `WITHCOORD` | No | No | Also return the longitude and latitude of each match. | +| `WITHDIST` | No | No | Also return the distance from the center, in the requested unit. | +| `WITHHASH` | No | No | Also return the raw 52-bit geohash score of each match. | +| `COUNT [ANY]` | No | No | Return at most `` matches. `ANY` returns as soon as enough matches are found, instead of sorting every match first. | +| `(ASC \| DESC)` | No | No | Sort the matches by distance from the center: `ASC` (nearest first) or `DESC` (farthest first). Unsorted when omitted. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string members or member-detail arrays | +| RESP3 | Array of bulk-string members or member-detail arrays | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +GEORADIUS_RO my-key 29.0 41.0 1.5 m +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.georadius_ro("my-key", 29.0, 41.0, 1.5, "M") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.georadius_ro("my-key", "29.0", "41.0", "1.5", "m"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.geoRadiusRo("my-key", { longitude: 29, latitude: 41 }, 1.5, "m"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.execute_command("GEORADIUS_RO", "my-key", "29.0", "41.0", "1.5", "m") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.GeoRadius(context.Background(), "my-key", 29.0, 41.0, &redis.GeoRadiusQuery{Radius: 1.5, Unit: "m"}).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.georadiusReadonly("my-key", 29.0, 41.0, 1.5, redis.clients.jedis.args.GeoUnit.M); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("GEORADIUS_RO"); + command.arg("my-key"); + command.arg("29.0"); + command.arg("41.0"); + command.arg("1.5"); + command.arg("m"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# GEORADIUSBYMEMBER +Source: https://upstash.com/docs/redis/commands/geo/georadiusbymember + + + Prefer [`GEOSEARCH`](/docs/redis/commands/geo/geosearch) with `FROMMEMBER` and `BYRADIUS` in new code: `GEOSEARCH FROMMEMBER BYRADIUS (m | km | ft | mi)`. In place of `STORE` and `STOREDIST`, use [`GEOSEARCHSTORE`](/docs/redis/commands/geo/geosearchstore) with the same query. + + +Use `GEORADIUSBYMEMBER` to find the members of a geospatial index that lie within a given radius of another member. + +It works exactly like [`GEORADIUS`](/docs/redis/commands/geo/georadius) except that the center is the stored position of a member instead of an explicit coordinate pair, which saves a lookup when the reference point is already in the index (a store, a driver, a landmark). The reference member itself always matches, since its distance from itself is zero, so remember to filter it out or ask for one result more than you need. + +The same `WITHCOORD`, `WITHDIST`, `WITHHASH`, `COUNT`, sorting, and `STORE` or `STOREDIST` options apply. + +## Syntax + +```redis +GEORADIUSBYMEMBER (m | km | ft | mi) + [WITHCOORD] + [WITHDIST] + [WITHHASH] + [COUNT [ANY]] + [ASC | DESC] + [STORE | STOREDIST ] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Member name. | +| `` | Yes | No | Search radius, in the unit given after it. | +| `(m \| km \| ft \| mi)` | Yes | No | Distance unit: `m` (meters), `km` (kilometers), `ft` (feet), or `mi` (miles). | +| `WITHCOORD` | No | No | Also return the longitude and latitude of each match. | +| `WITHDIST` | No | No | Also return the distance from the center, in the requested unit. | +| `WITHHASH` | No | No | Also return the raw 52-bit geohash score of each match. | +| `COUNT [ANY]` | No | No | Return at most `` matches. `ANY` returns as soon as enough matches are found, instead of sorting every match first. | +| `(ASC \| DESC)` | No | No | Sort the matches by distance from the center: `ASC` (nearest first) or `DESC` (farthest first). Unsorted when omitted. | +| `(STORE \| STOREDIST )` | No | No | Store the matches in a sorted set instead of returning them: `STORE` scores them by geohash, so the destination stays a geospatial index, and `STOREDIST` scores them by their distance from the center. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string members or member-detail arrays, or Integer when storing | +| RESP3 | Array of bulk-string members or member-detail arrays, or Integer when storing | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +GEORADIUSBYMEMBER my-key member 1.5 m +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.georadiusbymember("my-key", "member", 1.5, "M") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.georadiusbymember("my-key", "member", "1.5", "m"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.geoRadiusByMember("my-key", "member", 1.5, "m"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.georadiusbymember("my-key", "member", 1.5, "m") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.GeoRadiusByMember(context.Background(), "my-key", "member", &redis.GeoRadiusQuery{Radius: 1.5, Unit: "m"}).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.georadiusByMember("my-key", "member", 1.5, redis.clients.jedis.args.GeoUnit.M); + System.out.println(result); +} +``` + + + + + +```rust +use redis::geo::{RadiusOptions, Unit}; +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.geo_radius_by_member( + "my-key", + "member", + 1.5, + Unit::Meters, + RadiusOptions::default(), + )?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# GEORADIUSBYMEMBER_RO +Source: https://upstash.com/docs/redis/commands/geo/georadiusbymember-ro + + + Prefer [`GEOSEARCH`](/docs/redis/commands/geo/geosearch) with `FROMMEMBER` and `BYRADIUS` in new code: `GEOSEARCH FROMMEMBER BYRADIUS (m | km | ft | mi)`. + + +Use `GEORADIUSBYMEMBER_RO` to find members within a radius of another member. It is the read-only form of [`GEORADIUSBYMEMBER`](/docs/redis/commands/geo/georadiusbymember). + +The center is the stored position of the given member, which always appears among the matches at distance zero. The command accepts the same `WITHCOORD`, `WITHDIST`, `WITHHASH`, `COUNT`, and sorting options but has no `STORE` or `STOREDIST` clause, so it can be served on replicas and used from read-only scripts. + +## Syntax + +```redis +GEORADIUSBYMEMBER_RO (m | km | ft | mi) + [WITHCOORD] + [WITHDIST] + [WITHHASH] + [COUNT [ANY]] + [ASC | DESC] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Member name. | +| `` | Yes | No | Search radius, in the unit given after it. | +| `(m \| km \| ft \| mi)` | Yes | No | Distance unit: `m` (meters), `km` (kilometers), `ft` (feet), or `mi` (miles). | +| `WITHCOORD` | No | No | Also return the longitude and latitude of each match. | +| `WITHDIST` | No | No | Also return the distance from the center, in the requested unit. | +| `WITHHASH` | No | No | Also return the raw 52-bit geohash score of each match. | +| `COUNT [ANY]` | No | No | Return at most `` matches. `ANY` returns as soon as enough matches are found, instead of sorting every match first. | +| `(ASC \| DESC)` | No | No | Sort the matches by distance from the center: `ASC` (nearest first) or `DESC` (farthest first). Unsorted when omitted. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string members or member-detail arrays | +| RESP3 | Array of bulk-string members or member-detail arrays | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +GEORADIUSBYMEMBER_RO my-key member 1.5 m +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.georadiusbymember_ro("my-key", "member", 1.5, "M") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.georadiusbymember_ro("my-key", "member", "1.5", "m"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.geoRadiusByMemberRo("my-key", "member", 1.5, "m"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.execute_command("GEORADIUSBYMEMBER_RO", "my-key", "member", "1.5", "m") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.GeoRadiusByMember(context.Background(), "my-key", "member", &redis.GeoRadiusQuery{Radius: 1.5, Unit: "m"}).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.georadiusByMemberReadonly("my-key", "member", 1.5, redis.clients.jedis.args.GeoUnit.M); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("GEORADIUSBYMEMBER_RO"); + command.arg("my-key"); + command.arg("member"); + command.arg("1.5"); + command.arg("m"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# GEOSEARCH +Source: https://upstash.com/docs/redis/commands/geo/geosearch + +Use `GEOSEARCH` to find the members of a geospatial index that fall inside a circle or a rectangle. + +The center is either an existing member of the index (`FROMMEMBER`) or an explicit coordinate pair (`FROMLONLAT`). The area is either a circle of a given radius (`BYRADIUS`) or an axis-aligned box of a given width and height centered on that point (`BYBOX`), which is the shape to use when you are covering a map viewport rather than a "within N km" question. + +By default only member names come back. `WITHDIST` adds the distance from the center in the unit of the query, `WITHCOORD` the member's coordinates, and `WITHHASH` its raw geohash score. `ASC` and `DESC` sort by distance, and `COUNT` caps the number of results; adding `ANY` lets the server return as soon as it has enough matches, which is faster but no longer gives you the nearest ones. + +`GEOSEARCH` replaces the deprecated `GEORADIUS` and `GEORADIUSBYMEMBER` commands and is the command to use for new code. Use [`GEOSEARCHSTORE`](/docs/redis/commands/geo/geosearchstore) when the result should be stored instead of returned. + +## Syntax + +```redis +GEOSEARCH + (FROMMEMBER | FROMLONLAT ) + (BYRADIUS (m | km | ft | mi) | + BYBOX (m | km | ft | mi)) + [ASC | DESC] + [COUNT [ANY]] + [WITHCOORD] + [WITHDIST] + [WITHHASH] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `(FROMMEMBER \| FROMLONLAT )` | Yes | No | Where to center the search: `FROMMEMBER` uses the stored position of an existing member, `FROMLONLAT` uses the given coordinates. | +| `(BYRADIUS (m \| km \| ft \| mi) \| BYBOX (m \| km \| ft \| mi))` | Yes | No | The area to search: `BYRADIUS` a circle of the given radius, `BYBOX` an axis-aligned box of the given width and height centered on the search point. The unit is `m` (meters), `km` (kilometers), `ft` (feet), or `mi` (miles). | +| `(ASC \| DESC)` | No | No | Sort the matches by distance from the center: `ASC` (nearest first) or `DESC` (farthest first). Unsorted when omitted. | +| `COUNT [ANY]` | No | No | Return at most `` matches. `ANY` returns as soon as enough matches are found, instead of sorting every match first. | +| `WITHCOORD` | No | No | Also return the longitude and latitude of each match. | +| `WITHDIST` | No | No | Also return the distance from the center, in the requested unit. | +| `WITHHASH` | No | No | Also return the raw 52-bit geohash score of each match. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string members or member-detail arrays | +| RESP3 | Array of bulk-string members or member-detail arrays | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +GEOSEARCH my-key FROMMEMBER member BYRADIUS 1.5 m +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.geosearch( + "my-key", + { type: "FROMMEMBER", member: "member" }, + { type: "BYRADIUS", radius: 1.5, radiusType: "M" }, + "ASC", +); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.geosearch("my-key", member="member", radius=1.5, unit="M") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.geosearch("my-key", "FROMMEMBER", "member", "BYRADIUS", "1.5", "m"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.geoSearch("my-key", "member", { radius: 1.5, unit: "m" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.geosearch("my-key", member="member", radius=1.5, unit="m") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.GeoSearch(context.Background(), "my-key", &redis.GeoSearchQuery{Member: "member", Radius: 1.5, RadiusUnit: "m"}).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.geosearch("my-key", "member", 1.5, redis.clients.jedis.args.GeoUnit.M); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("GEOSEARCH"); + command.arg("my-key"); + command.arg("member"); + command.arg("1.5"); + command.arg("m"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# GEOSEARCHSTORE +Source: https://upstash.com/docs/redis/commands/geo/geosearchstore + +Use `GEOSEARCHSTORE` to run the same query as [`GEOSEARCH`](/docs/redis/commands/geo/geosearch) and store the matching members in another key instead of returning them. + +The destination is a sorted set holding the matches. By default their scores are the raw geohash values, so the destination is itself a valid geospatial index that can be queried further; with `STOREDIST` the score is the distance from the center in the unit of the query, which turns the result into a proximity-ordered list you can page through with [`ZRANGE`](/docs/redis/commands/sorted-set/zrange). + +The destination is overwritten on every call, and it is deleted when the query matches nothing. The reply is the number of members stored. This is the usual way to materialize a "nearby" result once and then reuse it for pagination or further set operations. + +## Syntax + +```redis +GEOSEARCHSTORE + (FROMMEMBER | FROMLONLAT ) + (BYRADIUS (m | km | ft | mi) | + BYBOX (m | km | ft | mi)) + [ASC | DESC] + [COUNT [ANY]] + [STOREDIST] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key used as destination. | +| `` | Yes | No | Redis key used as source. | +| `(FROMMEMBER \| FROMLONLAT )` | Yes | No | Where to center the search: `FROMMEMBER` uses the stored position of an existing member, `FROMLONLAT` uses the given coordinates. | +| `(BYRADIUS (m \| km \| ft \| mi) \| BYBOX (m \| km \| ft \| mi))` | Yes | No | The area to search: `BYRADIUS` a circle of the given radius, `BYBOX` an axis-aligned box of the given width and height centered on the search point. The unit is `m` (meters), `km` (kilometers), `ft` (feet), or `mi` (miles). | +| `(ASC \| DESC)` | No | No | Sort the matches by distance from the center: `ASC` (nearest first) or `DESC` (farthest first). Unsorted when omitted. | +| `COUNT [ANY]` | No | No | Return at most `` matches. `ANY` returns as soon as enough matches are found, instead of sorting every match first. | +| `STOREDIST` | No | No | Store each match's distance from the center instead of its geohash score. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +GEOSEARCHSTORE destination-key source-key FROMMEMBER member BYRADIUS 1.5 m +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.geosearchstore( + "destination-key", + "source-key", + { type: "FROMMEMBER", member: "member" }, + { type: "BYRADIUS", radius: 1.5, radiusType: "M" }, + "ASC", +); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.geosearchstore("destination-key", "source-key", member="member", radius=1.5, unit="M") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.geosearchstore("destination-key", "source-key", "FROMMEMBER", "member", "BYRADIUS", "1.5", "m"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.geoSearchStore("destination-key", "source-key", "member", { radius: 1.5, unit: "m" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.geosearchstore("destination-key", "source-key", member="member", radius=1.5, unit="m") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.GeoSearchStore(context.Background(), "source-key", "destination-key", &redis.GeoSearchStoreQuery{GeoSearchQuery: redis.GeoSearchQuery{Member: "member", Radius: 1.5, RadiusUnit: "m"}}).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.geosearchStore("destination-key", "source-key", "member", 1.5, redis.clients.jedis.args.GeoUnit.M); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("GEOSEARCHSTORE"); + command.arg("destination-key"); + command.arg("source-key"); + command.arg("member"); + command.arg("1.5"); + command.arg("m"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# Geo commands +Source: https://upstash.com/docs/redis/commands/geo/overview + + +Add geospatial items +Get distance between two members +Get geohash strings for members +Get coordinates of members +Find members within a radius of a point +Read-only radius query +Find members within a radius of another member +Read-only radius query by member +Search for members in an area +Store geosearch results + + +# HDEL +Source: https://upstash.com/docs/redis/commands/hash/hdel + +Use `HDEL` to remove one or more fields from a hash. + +The reply counts only the fields that were actually present, so deleting a field that is already gone is not an error. When the last field of a hash is removed the key itself is deleted, because Redis does not keep empty collections. + +## Syntax + +```redis +HDEL [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | Yes | Hash field name. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HDEL my-key field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hdel(key, 'field1', 'field2'); +// returns 5 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hdel("my-key", "field") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hdel("my-key", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hDel("my-key", "field"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hdel("my-key", "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HDel(context.Background(), "my-key", "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hdel("my-key", "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hdel("my-key", "field")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HEXISTS +Source: https://upstash.com/docs/redis/commands/hash/hexists + +Use `HEXISTS` to check whether a field is present in a hash. + +The reply is `1` when the field exists and `0` when either the field or the key is missing. Since the value is never transferred, this is the cheap way to test for presence, and it is also how you tell a missing field apart from a field whose value happens to be empty, which [`HGET`](/docs/redis/commands/hash/hget) cannot do. + +## Syntax + +```redis +HEXISTS +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Hash field name. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: `1` if the field exists, `0` otherwise | +| RESP3 | Integer: `1` if the field exists, `0` otherwise | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HEXISTS my-key field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("key", "field", "value"); +const exists = await redis.hexists("key", "field"); + +console.log(exists); // 1 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hexists("my-key", "field") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hexists("my-key", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hExists("my-key", "field"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hexists("my-key", "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HExists(context.Background(), "my-key", "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hexists("my-key", "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hexists("my-key", "field")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HEXPIRE +Source: https://upstash.com/docs/redis/commands/hash/hexpire + +Use `HEXPIRE` to give individual hash fields a lifetime in seconds, after which those fields are removed from the hash. + +Expiration here is per field, not per key: the hash itself stays alive as long as it still has fields, and the key is deleted automatically when the last surviving field expires. This makes it possible to keep short-lived and long-lived data in one hash, for example a user record whose verification code expires while the rest of the record stays. + +`FIELDS ` introduces the list of fields and the count must match the number of names that follow. The optional condition works as it does on [`EXPIRE`](/docs/redis/commands/generic/expire): `NX` only when the field has no expiration, `XX` only when it already has one, `GT` only when the new expiration is later than the current one, and `LT` only when it is earlier. + +The reply holds one status code per field, in order: `1` when the expiration was set, `0` when the condition prevented it, `2` when the field was deleted immediately because the given lifetime was zero or negative, and `-2` when the field does not exist. + +## Syntax + +```redis +HEXPIRE + [NX | XX | GT | LT] + FIELDS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Lifetime in seconds. | +| `(NX \| XX \| GT \| LT)` | No | No | Choose one form: `NX` (only when the field has no expiration); `XX` (only when the field already has one); `GT` (only when the new expiration is later than the current one); `LT` (only when it is earlier). | +| `FIELDS [ ...]` | Yes | No | Fields to target. Give the field count first, then that many field names. | + +## Important points + +* `NX` cannot be combined with `XX`, `GT`, or `LT`, and `GT` and `LT` cannot be used together. +* A field with no expiration counts as an infinite one, so `GT` never sets an expiration on such a field and `LT` always does. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer status codes, one per field | +| RESP3 | Array of integer status codes, one per field | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HEXPIRE my-key 1000 FIELDS 1 field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("my-key", "my-field", "my-value"); +const expirationSet = await redis.hexpire("my-key", "my-field", 1); + +console.log(expirationSet); // 1 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hexpire("my-key", "field", 1000) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hexpire("my-key", "1000", "FIELDS", "1", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hExpire("my-key", "field", 1000); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hexpire("my-key", 1000, "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HExpire(context.Background(), "my-key", 1000*time.Second, "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hexpire("my-key", 1000, "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hexpire("my-key", 1000, redis::ExpireOption::NONE, &["field"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HEXPIREAT +Source: https://upstash.com/docs/redis/commands/hash/hexpireat + +Use `HEXPIREAT` to schedule individual hash fields for deletion at a fixed point in time, given as a Unix timestamp in seconds. + +It is the absolute-deadline form of [`HEXPIRE`](/docs/redis/commands/hash/hexpire), which is what you want when several fields, or fields across several hashes, must expire at the same moment. A timestamp in the past removes the fields right away. The key is deleted when its last field expires. + +`FIELDS ` introduces the field list and the count must match. The optional condition applies the deadline only in certain cases: `NX` when the field has no expiration, `XX` when it already has one, `GT` when the new deadline is later than the current one, and `LT` when it is earlier. + +The reply holds one status code per field: `1` when the expiration was set, `0` when the condition prevented it, `2` when the field was deleted immediately, and `-2` when the field does not exist. + +## Syntax + +```redis +HEXPIREAT + [NX | XX | GT | LT] + FIELDS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Expiration time as a Unix timestamp in seconds. | +| `(NX \| XX \| GT \| LT)` | No | No | Choose one form: `NX` (only when the field has no expiration); `XX` (only when the field already has one); `GT` (only when the new expiration is later than the current one); `LT` (only when it is earlier). | +| `FIELDS [ ...]` | Yes | No | Fields to target. Give the field count first, then that many field names. | + +## Important points + +* `NX` cannot be combined with `XX`, `GT`, or `LT`, and `GT` and `LT` cannot be used together. +* A field with no expiration counts as an infinite one, so `GT` never sets an expiration on such a field and `LT` always does. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer status codes, one per field | +| RESP3 | Array of integer status codes, one per field | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HEXPIREAT my-key 1735689600 FIELDS 1 field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("my-key", "my-field", "my-value"); +const expirationSet = await redis.hexpireat("my-key", "my-field", Math.floor(Date.now() / 1000) + 10); + +console.log(expirationSet); // [1] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hexpireat("my-key", "field", 1735689600) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hexpireat("my-key", "1735689600", "FIELDS", "1", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hExpireAt("my-key", "field", 1735689600); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hexpireat("my-key", 1735689600, "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HExpireAt(context.Background(), "my-key", time.Unix(1735689600, 0), "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hexpireAt("my-key", 1735689600, "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hexpire_at("my-key", 1735689600, redis::ExpireOption::NONE, &["field"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HEXPIRETIME +Source: https://upstash.com/docs/redis/commands/hash/hexpiretime + +Use `HEXPIRETIME` to read the absolute expiration time of hash fields, as Unix timestamps in seconds. + +The reply holds one value per requested field, in order: the timestamp when the field expires, `-1` when the field exists but has no expiration, and `-2` when the field or the key does not exist. Use [`HTTL`](/docs/redis/commands/hash/httl) when you want the remaining lifetime instead of the deadline, and [`HPEXPIRETIME`](/docs/redis/commands/hash/hpexpiretime) for millisecond precision. + +## Syntax + +```redis +HEXPIRETIME FIELDS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `FIELDS [ ...]` | Yes | No | Fields to target. Give the field count first, then that many field names. | + +## Important points + +* Negative integer replies are sentinel values, not durations or timestamps; see the response description for missing or persistent data. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of expiration timestamps or negative integer status codes, one per field | +| RESP3 | Array of expiration timestamps or negative integer status codes, one per field | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HEXPIRETIME my-key FIELDS 1 field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("my-key", "my-field", "my-value"); +await redis.hexpireat("my-key", "my-field", Math.floor(Date.now() / 1000) + 10); +const expireTime = await redis.hexpiretime("my-key", "my-field"); + +console.log(expireTime); // e.g., [1697059200] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hexpiretime("my-key", "field") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hexpiretime("my-key", "FIELDS", "1", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hExpireTime("my-key", "field"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hexpiretime("my-key", "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HExpireTime(context.Background(), "my-key", "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hexpireTime("my-key", "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hexpire_time("my-key", &["field"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HGET +Source: https://upstash.com/docs/redis/commands/hash/hget + +Use `HGET` to read the value of a single field of a hash. + +The reply is null when either the field or the whole key is missing, so the two cases cannot be told apart from the reply alone; use [`HEXISTS`](/docs/redis/commands/hash/hexists) when that difference matters. To read several fields use [`HMGET`](/docs/redis/commands/hash/hmget) rather than repeated calls, and to read all of them use [`HGETALL`](/docs/redis/commands/hash/hgetall). + +## Syntax + +```redis +HGET +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Hash field name. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string or Null bulk string or null array | +| RESP3 | Bulk string or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HGET my-key field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("key", {field: "value"}); +const field = await redis.hget("key", "field"); +console.log(field); // "value" +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hget("my-key", "field") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hget("my-key", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hGet("my-key", "field"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hget("my-key", "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HGet(context.Background(), "my-key", "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hget("my-key", "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hget("my-key", "field")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HGETALL +Source: https://upstash.com/docs/redis/commands/hash/hgetall + +Use `HGETALL` to read every field and value of a hash in one call. + +The reply pairs each field with its value. RESP2 flattens it into a single alternating array while RESP3 returns a map, and client libraries normally decode either form into a native dictionary. A missing key returns an empty result rather than an error. + +The whole hash is transferred, so on hashes with many fields prefer [`HMGET`](/docs/redis/commands/hash/hmget) when you know which fields you need, or [`HSCAN`](/docs/redis/commands/hash/hscan) to walk the hash in batches. + +## Syntax + +```redis +HGETALL +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | + +## Important points + +* Pair-based results may be flattened into one alternating array in RESP2 while RESP3 preserves nested pairs or a map. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Flat array of alternating keys and values | +| RESP3 | Map | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HGETALL my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("key", { + field1: "value1", + field2: "value2", + }); +const hash = await redis.hgetall("key"); +console.log(hash); // { field1: "value1", field2: "value2" } +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hgetall("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hgetall("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hGetAll("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hgetall("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HGetAll(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hgetAll("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hgetall("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HGETDEL +Source: https://upstash.com/docs/redis/commands/hash/hgetdel + +Use `HGETDEL` to read hash fields and delete them in the same atomic step. + +The reply holds the previous value of each requested field, in the order requested, with null for fields that were not present. Reading and removing together removes the race that an [`HGET`](/docs/redis/commands/hash/hget) followed by an [`HDEL`](/docs/redis/commands/hash/hdel) would leave open, which makes the command a good fit for one-shot values such as one-time codes, claim tickets, or queued items keyed by name: exactly one caller gets the value. + +`FIELDS ` introduces the field list and the count must match. The key is deleted when its last field is removed. + +## Syntax + +```redis +HGETDEL FIELDS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `FIELDS [ ...]` | Yes | No | Fields to target. Give the field count first, then that many field names. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string values or null values, one per field | +| RESP3 | Array of bulk-string values or null values, one per field | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HGETDEL my-key FIELDS 1 field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +// Set some hash fields +await redis.hset("user:123", { name: "John", age: "30", email: "john@example.com" }); + +// Get and delete specific fields +const result = await redis.hgetdel("user:123", "name", "email"); +console.log(result); // { name: "John", email: "john@example.com" } + +// Verify fields were deleted +const name = await redis.hget("user:123", "name"); +console.log(name); // null +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hgetdel("my-key", "field") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hgetdel("my-key", "FIELDS", "1", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hGetDel("my-key", "field"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hgetdel("my-key", "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HGetDel(context.Background(), "my-key", "1", "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hgetdel("my-key", "1", "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hget_del("my-key", &["field"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HGETEX +Source: https://upstash.com/docs/redis/commands/hash/hgetex + +Use `HGETEX` to read hash fields and change their expiration in the same call. + +Without an expiration option it simply returns the values, like [`HMGET`](/docs/redis/commands/hash/hmget). `EX`, `PX`, `EXAT`, and `PXAT` give every requested field a new lifetime or deadline, and `PERSIST` removes the expiration so the fields stop expiring altogether. + +Doing both in one command is what makes sliding expirations possible per field: reading a session attribute can extend it, with no window in which another client sees the field without its refreshed lifetime. `FIELDS ` introduces the field list and the count must match. + +## Syntax + +```redis +HGETEX + [EX | PX | EXAT | + PXAT | PERSIST] + FIELDS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `(EX \| PX \| EXAT \| PXAT \| PERSIST)` | No | No | Choose one form: `EX` (set a lifetime in seconds); `PX` (set a lifetime in milliseconds); `EXAT` (expire at a Unix timestamp in seconds); `PXAT` (expire at a Unix timestamp in milliseconds); `PERSIST` (remove the expiration). Left unchanged when omitted. | +| `FIELDS [ ...]` | Yes | No | Fields to target. Give the field count first, then that many field names. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string values or null values, one per field | +| RESP3 | Array of bulk-string values or null values, one per field | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HGETEX my-key FIELDS 1 field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("user:123", { name: "John", email: "john@example.com" }); + +// Get fields and set expiration to 60 seconds +const result = await redis.hgetex("user:123", { ex: 60 }, "name", "email"); +console.log(result); // { name: "John", email: "john@example.com" } +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hgetex("my-key", "field") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hgetex("my-key", "FIELDS", "1", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hGetEx("my-key", "field"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hgetex("my-key", "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HGetEX(context.Background(), "my-key", "1", "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hgetex("my-key", redis.clients.jedis.params.HGetExParams.hGetExParams(), "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hget_ex("my-key", &["field"], redis::Expiry::PERSIST)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HINCRBY +Source: https://upstash.com/docs/redis/commands/hash/hincrby + +Use `HINCRBY` to add an integer to the number stored in a hash field and get the result. + +A missing field, or a missing key, is treated as `0`, so the first call creates the hash and the field. The increment may be negative to count down. The stored value must be the string form of a 64-bit signed integer; anything else returns an error, as does an operation that would overflow the range. + +Reading, adding, and writing back happen as one atomic step, so concurrent callers each receive a distinct result and no update is lost. That makes hashes a compact way to keep many related counters, such as per-status counts for one entity, under a single key. + +## Syntax + +```redis +HINCRBY +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Hash field name. | +| `` | Yes | No | Integer amount to add to the field. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HINCRBY my-key field 1 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("key", { + field: 20, + }); +const after = await redis.hincrby("key", "field", 2); +console.log(after); // 22 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hincrby("my-key", "field", 1) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hincrby("my-key", "field", "1"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hIncrBy("my-key", "field", 1); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hincrby("my-key", "field", 1) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HIncrBy(context.Background(), "my-key", "field", 1).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hincrBy("my-key", "field", 1); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hincr("my-key", "field", 1)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HINCRBYFLOAT +Source: https://upstash.com/docs/redis/commands/hash/hincrbyfloat + +Use `HINCRBYFLOAT` to add a floating point number to the value of a hash field and get the result. + +The stored value and the increment are parsed as double precision floats, and a missing field or key counts as `0`. The increment may be negative, and there is no separate decrement command. A value that is not a valid number returns an error. + +The reply is the new value as a string, which client libraries usually decode into a native number. Note that the result is stored in the same textual form, so repeated increments of values that cannot be represented exactly in binary floating point accumulate the usual rounding error; keep money and similar quantities in integer units and use [`HINCRBY`](/docs/redis/commands/hash/hincrby). + +## Syntax + +```redis +HINCRBYFLOAT +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Hash field name. | +| `` | Yes | No | Amount to add to the field; may be a floating-point number. | + +## Important points + +* The value is always returned as a bulk string, in both RESP2 and RESP3. Client libraries commonly decode it to a language number. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string | +| RESP3 | Bulk string | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HINCRBYFLOAT my-key field 1.5 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("key", { + field: 20, + }); +const after = await redis.hincrby("key", "field", 2.5); +console.log(after); // 22.5 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hincrbyfloat("my-key", "field", 1.5) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hincrbyfloat("my-key", "field", "1.5"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hIncrByFloat("my-key", "field", 1.5); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hincrbyfloat("my-key", "field", 1.5) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HIncrByFloat(context.Background(), "my-key", "field", 1.5).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hincrByFloat("my-key", "field", 1.5); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hincr("my-key", "field", 1.5)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HKEYS +Source: https://upstash.com/docs/redis/commands/hash/hkeys + +Use `HKEYS` to get the names of all the fields in a hash, without their values. + +A missing key returns an empty list. The whole field list is built and transferred in one reply, so on large hashes prefer [`HSCAN`](/docs/redis/commands/hash/hscan) with `NOVALUES`, which walks the field names in batches instead. + +## Syntax + +```redis +HKEYS +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string fields | +| RESP3 | Array of bulk-string fields | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HKEYS my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("key", { + id: 1, + username: "chronark", + }); +const fields = await redis.hkeys("key"); +console.log(fields); // ["id", "username"] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hkeys("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hkeys("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hKeys("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hkeys("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HKeys(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hkeys("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hkeys("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HLEN +Source: https://upstash.com/docs/redis/commands/hash/hlen + +Use `HLEN` to get the number of fields in a hash. + +The reply is `0` when the key does not exist. The count is kept by Redis rather than computed, so it is cheap whatever the size of the hash, which makes it the right way to check how big a hash has grown before deciding to read or iterate it. + +## Syntax + +```redis +HLEN +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HLEN my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("key", { + id: 1, + username: "chronark", + }); +const fields = await redis.hlen("key"); +console.log(fields); // 2 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hlen("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hlen("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hLen("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hlen("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HLen(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hlen("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hlen("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HMGET +Source: https://upstash.com/docs/redis/commands/hash/hmget + +Use `HMGET` to read several fields of a hash in one call. + +The reply holds one entry per requested field, in the order requested, with null for fields that do not exist. Asking for fields of a key that does not exist returns a list of nulls rather than an error, so the shape of the reply is always predictable and can be zipped back onto your list of field names. + +It saves the round trips of repeated [`HGET`](/docs/redis/commands/hash/hget) calls and transfers far less than [`HGETALL`](/docs/redis/commands/hash/hgetall) when you only need a few fields of a large hash. + +## Syntax + +```redis +HMGET [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | Yes | Hash field name. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string values or null values, one per field | +| RESP3 | Array of bulk-string values or null values, one per field | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HMGET my-key field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("key", { + id: 1, + username: "chronark", + name: "andreas" + }); +const fields = await redis.hmget("key", "username", "name"); +console.log(fields); // { username: "chronark", name: "andreas" } +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hmget("my-key", "field") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hmget("my-key", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hmGet("my-key", "field"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hmget("my-key", ["field"]) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HMGet(context.Background(), "my-key", "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hmget("my-key", "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hmget("my-key", &["field"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HMSET +Source: https://upstash.com/docs/redis/commands/hash/hmset + + + Prefer [`HSET`](/docs/redis/commands/hash/hset) with multiple field-value pairs in new code: `HSET [ ...]`. + + +Use `HMSET` to set several field and value pairs of a hash in one call, creating the key if it does not exist. + +Existing fields are overwritten and the reply is always `OK`, so it says nothing about what changed. [`HSET`](/docs/redis/commands/hash/hset) accepts multiple pairs as well and additionally reports how many fields were new, so prefer it in new code. + +## Syntax + +```redis +HMSET [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| ` ` | Yes | Yes | Field and the value to store in it. Repeat to set several fields in one call. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HMSET my-key field value +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.hmset("my-key", { field: "value" }); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hmset("my-key", {"field": "value"}) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hmset("my-key", "field", "value"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hSet("my-key", { field: "value" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hset("my-key", mapping={"field": "value"}) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HMSet(context.Background(), "my-key", "field", "value").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hmset("my-key", java.util.Map.of("field", "value")); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hset_multiple("my-key", &[("field", "value")])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HPERSIST +Source: https://upstash.com/docs/redis/commands/hash/hpersist + +Use `HPERSIST` to remove the expiration from hash fields so that they stop being deleted automatically. + +The reply holds one status code per requested field, in order: `1` when an expiration was removed, `-1` when the field exists but had no expiration, and `-2` when the field or the key does not exist. This is how a field set by [`HEXPIRE`](/docs/redis/commands/hash/hexpire) or [`HSETEX`](/docs/redis/commands/hash/hsetex) is promoted from temporary to permanent without rewriting its value. + +`FIELDS ` introduces the field list and the count must match. + +## Syntax + +```redis +HPERSIST FIELDS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `FIELDS [ ...]` | Yes | No | Fields to target. Give the field count first, then that many field names. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer status codes, one per field | +| RESP3 | Array of integer status codes, one per field | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HPERSIST my-key FIELDS 1 field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("my-key", "my-field", "my-value"); +await redis.hpexpire("my-key", "my-field", 1000); + +const expirationRemoved = await redis.hpersist("my-key", "my-field"); + +console.log(expirationRemoved); // [1] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hpersist("my-key", "field") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hpersist("my-key", "FIELDS", "1", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hPersist("my-key", "field"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hpersist("my-key", "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HPersist(context.Background(), "my-key", "1", "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hpersist("my-key", "1", "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hpersist("my-key", &["field"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HPEXPIRE +Source: https://upstash.com/docs/redis/commands/hash/hpexpire + +Use `HPEXPIRE` to give individual hash fields a lifetime in milliseconds, after which those fields are removed from the hash. + +It is the millisecond form of [`HEXPIRE`](/docs/redis/commands/hash/hexpire) and behaves identically otherwise: expiration is per field, the hash survives as long as it has fields, and the key disappears when the last field expires. The finer precision matters for short-lived fields such as per-field locks or rate limit windows. + +`FIELDS ` introduces the field list and the count must match. The optional condition applies the new lifetime only in certain cases: `NX` when the field has no expiration, `XX` when it already has one, `GT` when the new expiration is later than the current one, and `LT` when it is earlier. The reply holds one status code per field: `1` when set, `0` when the condition prevented it, `2` when the field was deleted immediately, and `-2` when it does not exist. + +## Syntax + +```redis +HPEXPIRE + [NX | XX | GT | LT] + FIELDS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Lifetime in milliseconds. | +| `(NX \| XX \| GT \| LT)` | No | No | Choose one form: `NX` (only when the field has no expiration); `XX` (only when the field already has one); `GT` (only when the new expiration is later than the current one); `LT` (only when it is earlier). | +| `FIELDS [ ...]` | Yes | No | Fields to target. Give the field count first, then that many field names. | + +## Important points + +* `NX` cannot be combined with `XX`, `GT`, or `LT`, and `GT` and `LT` cannot be used together. +* A field with no expiration counts as an infinite one, so `GT` never sets an expiration on such a field and `LT` always does. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer status codes, one per field | +| RESP3 | Array of integer status codes, one per field | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HPEXPIRE my-key 1000 FIELDS 1 field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("my-key", "my-field", "my-value"); +const expirationSet = await redis.hpexpire("my-key", "my-field", 1000); + +console.log(expirationSet); // [1] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hpexpire("my-key", "field", 1000) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hpexpire("my-key", "1000", "FIELDS", "1", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hpExpire("my-key", "field", 1000); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hpexpire("my-key", 1000, "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HPExpire(context.Background(), "my-key", time.Second, "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hpexpire("my-key", 1000, "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hpexpire("my-key", 1000, redis::ExpireOption::NONE, &["field"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HPEXPIREAT +Source: https://upstash.com/docs/redis/commands/hash/hpexpireat + +Use `HPEXPIREAT` to schedule individual hash fields for deletion at a fixed point in time, given as a Unix timestamp in milliseconds. + +It combines the absolute deadline of [`HEXPIREAT`](/docs/redis/commands/hash/hexpireat) with millisecond precision, which is what you need when fields spread over several hashes have to expire at exactly the same instant. A timestamp in the past removes the fields right away, and the key is deleted when its last field expires. + +`FIELDS ` introduces the field list and the count must match. The optional condition applies the deadline only when the field has no expiration (`NX`), already has one (`XX`), or when the new deadline is later (`GT`) or earlier (`LT`) than the current one. The reply holds one status code per field: `1` when set, `0` when the condition prevented it, `2` when the field was deleted immediately, and `-2` when it does not exist. + +## Syntax + +```redis +HPEXPIREAT + [NX | XX | GT | LT] + FIELDS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Expiration time as a Unix timestamp in milliseconds. | +| `(NX \| XX \| GT \| LT)` | No | No | Choose one form: `NX` (only when the field has no expiration); `XX` (only when the field already has one); `GT` (only when the new expiration is later than the current one); `LT` (only when it is earlier). | +| `FIELDS [ ...]` | Yes | No | Fields to target. Give the field count first, then that many field names. | + +## Important points + +* `NX` cannot be combined with `XX`, `GT`, or `LT`, and `GT` and `LT` cannot be used together. +* A field with no expiration counts as an infinite one, so `GT` never sets an expiration on such a field and `LT` always does. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer status codes, one per field | +| RESP3 | Array of integer status codes, one per field | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HPEXPIREAT my-key 1735689600 FIELDS 1 field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("my-key", "my-field", "my-value"); +const expirationSet = await redis.hpexpireat("my-key", "my-field", Date.now() + 1000); + +console.log(expirationSet); // [1] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hpexpireat("my-key", "field", 1735689600) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hpexpireat("my-key", "1735689600", "FIELDS", "1", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hpExpireAt("my-key", "field", 1735689600); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hpexpireat("my-key", 1735689600, "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HPExpireAt(context.Background(), "my-key", time.UnixMilli(1735689600), "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hpexpireAt("my-key", 1735689600, "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hpexpire_at("my-key", 1735689600, redis::ExpireOption::NONE, &["field"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HPEXPIRETIME +Source: https://upstash.com/docs/redis/commands/hash/hpexpiretime + +Use `HPEXPIRETIME` to read the absolute expiration time of hash fields, as Unix timestamps in milliseconds. + +The reply holds one value per requested field, in order: the timestamp at which it expires, `-1` when the field exists but has no expiration, and `-2` when the field or the key does not exist. It is the millisecond form of [`HEXPIRETIME`](/docs/redis/commands/hash/hexpiretime) and reports a deadline rather than the time left, which is the value to compare against a clock. + +## Syntax + +```redis +HPEXPIRETIME FIELDS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `FIELDS [ ...]` | Yes | No | Fields to target. Give the field count first, then that many field names. | + +## Important points + +* Negative integer replies are sentinel values, not durations or timestamps; see the response description for missing or persistent data. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of expiration timestamps or negative integer status codes, one per field | +| RESP3 | Array of expiration timestamps or negative integer status codes, one per field | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HPEXPIRETIME my-key FIELDS 1 field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("my-key", "my-field", "my-value"); +await redis.hpexpireat("my-key", "my-field", Date.now() + 1000); +const expireTime = await redis.hpexpiretime("my-key", "my-field"); + +console.log(expireTime); // e.g., 1697059200000 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hpexpiretime("my-key", "field") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hpexpiretime("my-key", "FIELDS", "1", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hpExpireTime("my-key", "field"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hpexpiretime("my-key", "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HPExpireTime(context.Background(), "my-key", "1", "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hpexpireTime("my-key", "1", "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hpexpire_time("my-key", &["field"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HPTTL +Source: https://upstash.com/docs/redis/commands/hash/hpttl + +Use `HPTTL` to read how much longer hash fields will live, in milliseconds. + +The reply holds one value per requested field, in order: the remaining lifetime, `-1` when the field exists but has no expiration, and `-2` when the field or the key does not exist. It is the millisecond form of [`HTTL`](/docs/redis/commands/hash/httl), and the extra precision matters for fields that live for less than a second. + +## Syntax + +```redis +HPTTL FIELDS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `FIELDS [ ...]` | Yes | No | Fields to target. Give the field count first, then that many field names. | + +## Important points + +* Negative integer replies are sentinel values, not durations or timestamps; see the response description for missing or persistent data. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of TTL values or negative integer status codes, one per field | +| RESP3 | Array of TTL values or negative integer status codes, one per field | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HPTTL my-key FIELDS 1 field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("my-key", "my-field", "my-value"); +await redis.hpexpire("my-key", "my-field", 1000); +const ttl = await redis.hpttl("my-key", "my-field"); + +console.log(ttl); // e.g., [950] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hpttl("my-key", "field") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hpttl("my-key", "FIELDS", "1", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hpTTL("my-key", "field"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hpttl("my-key", "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HPTTL(context.Background(), "my-key", "1", "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hpttl("my-key", "1", "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hpttl("my-key", &["field"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HRANDFIELD +Source: https://upstash.com/docs/redis/commands/hash/hrandfield + +Use `HRANDFIELD` to get one or more random fields from a hash. + +Without a count a single field name is returned, or null when the key does not exist. A positive count returns up to that many distinct fields, capped at the size of the hash, while a negative count returns exactly that many fields chosen independently, so the same field can come up more than once. `WITHVALUES` returns each field together with its value. + +Nothing is removed from the hash, which is the difference from [`HGETDEL`](/docs/redis/commands/hash/hgetdel): use this for sampling, random selection, and quick inspection of an unfamiliar hash. + +## Syntax + +```redis +HRANDFIELD [ [WITHVALUES]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| ` [WITHVALUES]` | No | No | Number of fields to return; a negative count may repeat fields. `WITHVALUES` also returns each field's value. | + +## Important points + +* Pair-based results may be flattened into one alternating array in RESP2 while RESP3 preserves nested pairs or a map. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Null bulk string or null array, Bulk string, array of fields, or flat field/value array | +| RESP3 | Null, Bulk string, array of fields, or array of field/value pairs | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HRANDFIELD my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("key", { + id: 1, + username: "chronark", + name: "andreas" + }); +const randomField = await redis.hrandfield("key"); +console.log(randomField); // one of "id", "username" or "name" +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hrandfield("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hrandfield("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hRandField("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hrandfield("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HRandField(context.Background(), "my-key", 1).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hrandfield("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("HRANDFIELD"); + command.arg("my-key"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HSCAN +Source: https://upstash.com/docs/redis/commands/hash/hscan + +Use `HSCAN` to iterate the fields of a hash in batches instead of reading it all at once. + +Each call takes a cursor and returns the next cursor together with a batch of field and value pairs. Start at cursor `0` and keep calling with the cursor from the previous reply until the server returns `0`, which ends the iteration. Because each call does a bounded amount of work, this avoids the long single reply that [`HGETALL`](/docs/redis/commands/hash/hgetall) produces on a large hash. + +`MATCH` filters field names with a glob-style pattern, `COUNT` hints at how much work each call should do, and `NOVALUES` returns field names only, which is noticeably cheaper when values are large and you do not need them. Filtering is applied after a batch has been read, so a call can return nothing while the cursor is still non-zero: only a cursor of `0` means the iteration is over. Fields present for the whole iteration are returned at least once, and fields added or removed while it runs may or may not appear. + +## Syntax + +```redis +HSCAN [MATCH ] [COUNT ] [NOVALUES] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Cursor returned by the previous call; start at `0`. | +| `MATCH ` | No | No | Return only elements matching this glob-style pattern. | +| `COUNT ` | No | No | Hint for how much work each iteration should do. | +| `NOVALUES` | No | No | Return only field names, without their values. | + +## Important points + +* This operation can inspect a large part of the database. Prefer cursor-based scans where possible and avoid unbounded use on hot paths. +* The cursor is opaque. Start with `0` and continue until the server returns cursor `0`; a single iteration may return no elements. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Two-element array: cursor and flat field/value array, or field array with `NOVALUES` | +| RESP3 | Two-element array: cursor and flat field/value array, or field array with `NOVALUES` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HSCAN my-key 0 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("key", { + id: 1, + username: "chronark", + name: "andreas" + }); +const [newCursor, fields] = await redis.hscan("key", 0); +console.log(newCursor); // likely `0` since this is a very small hash +console.log(fields); // ["id", 1, "username", "chronark", "name", "andreas"] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hscan("my-key", 0) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hscan("my-key", "0"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hScan("my-key", "0"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hscan("my-key", 0) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, _, err := client.HScan(context.Background(), "my-key", 0, "*", 0).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hscan("my-key", "0"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let iter: redis::Iter<(String, String)> = connection.hscan("my-key")?; + for (field, value) in iter { + println!("{field}: {value}"); + } + Ok(()) +} +``` + + + + + +# HSET +Source: https://upstash.com/docs/redis/commands/hash/hset + +Use `HSET` to set one or more fields of a hash to the given values, creating the key when it does not exist. + +Existing fields are overwritten, and the reply counts only the fields that were added, not those that were updated, which is how you tell an insert from an update. Setting fields does not touch the key's time to live, so a hash with an expiration keeps it as it is written to. A field's own expiration is a different matter: writing a field clears the TTL it may have been given by [`HEXPIRE`](/docs/redis/commands/hash/hexpire) or [`HSETEX`](/docs/redis/commands/hash/hsetex). + +Hashes are the compact way to store an object under one key: field access with `HSET` and [`HGET`](/docs/redis/commands/hash/hget) avoids reading and rewriting the whole value the way a serialized string would. + +## Syntax + +```redis +HSET [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| ` ` | Yes | Yes | Field and the value to store in it. Repeat to set several fields in one call. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HSET my-key field value +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("key", { + id: 1, + username: "chronark", + name: "andreas" + }); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hset("my-key", "field", "value") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hset("my-key", "field", "value"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hSet("my-key", "field", "value"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hset("my-key", "field", "value") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HSet(context.Background(), "my-key", "field", "value").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hset("my-key", "field", "value"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hset("my-key", "field", "value")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HSETEX +Source: https://upstash.com/docs/redis/commands/hash/hsetex + +Use `HSETEX` to write hash fields and set their expiration in the same atomic call. + +`FIELDS ` introduces the field and value pairs and the count must match. `EX`, `PX`, `EXAT`, and `PXAT` give the written fields a lifetime or an absolute deadline, and `KEEPTTL` keeps whatever expiration those fields already had. Without any of these options the fields are written without an expiration, so a previously set one is dropped. + +`FNX` writes only when none of the given fields exist and `FXX` only when all of them do, which turns the command into an atomic conditional write: create-if-absent or update-if-present, with the expiration applied in the same step. The reply is `1` when the fields were written and `0` when the condition prevented it. + +## Syntax + +```redis +HSETEX + [FNX | FXX] + [EX | PX | EXAT | + PXAT | KEEPTTL] + FIELDS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `(FNX \| FXX)` | No | No | Write only when the condition holds: `FNX` when none of the given fields exist, `FXX` when all of them do. | +| `(EX \| PX \| EXAT \| PXAT \| KEEPTTL)` | No | No | Choose one form: `EX` (set a lifetime in seconds); `PX` (set a lifetime in milliseconds); `EXAT` (expire at a Unix timestamp in seconds); `PXAT` (expire at a Unix timestamp in milliseconds); `KEEPTTL` (preserve the existing key lifetime). | +| `FIELDS [ ...]` | Yes | No | Field-value pairs to set. Give the pair count first, then that many field and value pairs. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: `1` if the fields were set, `0` otherwise | +| RESP3 | Integer: `1` if the fields were set, `0` otherwise | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HSETEX my-key FIELDS 1 field value +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +// Set fields with 1 hour expiration +await redis.hsetex("user:123", { expiration: { ex: 3600 } }, { + name: "John", + email: "john@example.com" +}); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hsetex("my-key", field="field", value="value") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hsetex("my-key", "FIELDS", "1", "field", "value"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hSetEx("my-key", { field: "value" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hsetex("my-key", mapping={"field": "value"}) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HSetEX(context.Background(), "my-key", "1", "field", "value").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hsetex("my-key", redis.clients.jedis.params.HSetExParams.hSetExParams(), "field", "value"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::{HashFieldExpirationOptions, TypedCommands}; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hset_ex( + "my-key", + &HashFieldExpirationOptions::default(), + &[("field", "value")], + )?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HSETNX +Source: https://upstash.com/docs/redis/commands/hash/hsetnx + +Use `HSETNX` to set a hash field only when it does not already exist. + +The reply is `1` when the field was created and `0` when it was already present and left untouched. The check and the write happen atomically, so of several clients racing to fill the same field exactly one succeeds, which makes the command a way to claim a slot inside a hash without overwriting whatever a concurrent writer put there. + +## Syntax + +```redis +HSETNX +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Hash field name. | +| `` | Yes | No | Value to store in the field. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: `1` if the field was set, `0` if it already exists | +| RESP3 | Integer: `1` if the field was set, `0` if it already exists | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HSETNX my-key field value +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hsetnx("key", "id", 1) +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hsetnx("my-key", "field", "value") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hsetnx("my-key", "field", "value"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hSetNX("my-key", "field", "value"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hsetnx("my-key", "field", "value") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HSetNX(context.Background(), "my-key", "field", "value").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hsetnx("my-key", "field", "value"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hset_nx("my-key", "field", "value")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HSTRLEN +Source: https://upstash.com/docs/redis/commands/hash/hstrlen + +Use `HSTRLEN` to get the length in bytes of the value stored in a hash field. + +The reply is `0` when either the field or the key is missing. Since the value itself is not transferred, this is how you check the size of a large field, or decide whether it is worth fetching, without paying for it. + +## Syntax + +```redis +HSTRLEN +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Hash field name. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HSTRLEN my-key field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const length = await redis.hstrlen("key", "field") +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hstrlen("my-key", "field") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hstrlen("my-key", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hStrLen("my-key", "field"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hstrlen("my-key", "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HStrLen(context.Background(), "my-key", "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hstrlen("my-key", "field"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("HSTRLEN"); + command.arg("my-key"); + command.arg("field"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HTTL +Source: https://upstash.com/docs/redis/commands/hash/httl + +Use `HTTL` to read how much longer hash fields will live, in seconds. + +The reply holds one value per requested field, in order: the remaining lifetime, `-1` when the field exists but has no expiration, and `-2` when the field or the key does not exist, so a missing field is never confused with a permanent one. Use [`HPTTL`](/docs/redis/commands/hash/hpttl) for millisecond precision and [`HEXPIRETIME`](/docs/redis/commands/hash/hexpiretime) when you want the absolute deadline instead of the time left. + +## Syntax + +```redis +HTTL FIELDS [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `FIELDS [ ...]` | Yes | No | Fields to target. Give the field count first, then that many field names. | + +## Important points + +* Negative integer replies are sentinel values, not durations or timestamps; see the response description for missing or persistent data. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of TTL values or negative integer status codes, one per field | +| RESP3 | Array of TTL values or negative integer status codes, one per field | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HTTL my-key FIELDS 1 field +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("my-key", "my-field", "my-value"); +await redis.hexpire("my-key", "my-field", 10); +const ttl = await redis.httl("my-key", "my-field"); + +console.log(ttl); // e.g., [9] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.httl("my-key", "field") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.httl("my-key", "FIELDS", "1", "field"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hTTL("my-key", "field"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.httl("my-key", "field") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HTTL(context.Background(), "my-key", "1", "field").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.httl("my-key", "1", "field"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.httl("my-key", &["field"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# HVALS +Source: https://upstash.com/docs/redis/commands/hash/hvals + +Use `HVALS` to get all the values in a hash, without their field names. + +A missing key returns an empty list, and values come back in no particular order. The whole hash is transferred, so on large hashes prefer [`HSCAN`](/docs/redis/commands/hash/hscan) to walk it in batches, or [`HMGET`](/docs/redis/commands/hash/hmget) when you know which fields you need. + +## Syntax + +```redis +HVALS +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string values | +| RESP3 | Array of bulk-string values | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +HVALS my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.hset("key", { + field1: "Hello", + field2: "World", +}) +const values = await redis.hvals("key") +console.log(values) // ["Hello", "World"] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.hvals("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.hvals("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.hVals("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.hvals("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.HVals(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.hvals("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.hvals("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# Hash commands +Source: https://upstash.com/docs/redis/commands/hash/overview + + +Delete one or more hash fields +Check if a hash field exists +Set field TTL in seconds +Set field expiry as timestamp +Get field expiry as timestamp +Get the value of a hash field +Get all fields and values +Get and delete hash fields +Get fields and set their expiry +Increment integer value of a field +Increment float value of a field +Get all fields in a hash +Get number of fields in a hash +Get values of multiple fields +Set multiple hash fields +Remove field expiration +Set field TTL in milliseconds +Set field expiry as ms timestamp +Get field expiry as ms timestamp +Get field TTL in milliseconds +Get random fields from a hash +Incrementally iterate hash fields +Set hash field values +Set fields with expiration +Set field only if it doesn't exist +Get length of a field's value +Get field TTL in seconds +Get all values in a hash + + +# HyperLogLog commands +Source: https://upstash.com/docs/redis/commands/hyperloglog/overview + + +Add elements to HyperLogLog +Get estimated cardinality +Merge multiple HyperLogLogs + + +# PFADD +Source: https://upstash.com/docs/redis/commands/hyperloglog/pfadd + +Use `PFADD` to add elements to a HyperLogLog. + +A HyperLogLog estimates how many distinct items it has seen while using a small, fixed amount of memory (at most about 12 KB) no matter how many elements pass through it. That is the trade it makes: individual elements are not stored, so they cannot be listed, checked for membership, or removed, and the cardinality that comes back from [`PFCOUNT`](/docs/redis/commands/hyperloglog/pfcount) is an approximation with a standard error of about 0.81%. + +The key is created on first use, and the reply is `1` when the internal registers changed as a result of the call, which is a hint that at least one element was new, and `0` when they did not. Calling `PFADD` with no elements creates an empty HyperLogLog if the key does not exist yet. Use it for counts where the exact number does not matter, such as unique visitors per page or per day, and a set for cases where you must be able to look elements up. + +## Syntax + +```redis +PFADD [ [ ...]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | No | Yes | Element to add to the HyperLogLog. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: `1` if at least one internal register was altered, `0` otherwise | +| RESP3 | Integer: `1` if at least one internal register was altered, `0` otherwise | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PFADD my-key element +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.pfadd("my-key", "element"); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.pfadd("my-key", "member") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.pfadd("my-key", "element"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.pfAdd("my-key", "element"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.pfadd("my-key", "member") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.PFAdd(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.pfadd("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.pfadd("my-key", &["member"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# PFCOUNT +Source: https://upstash.com/docs/redis/commands/hyperloglog/pfcount + +Use `PFCOUNT` to read the estimated number of distinct elements recorded in one or more HyperLogLogs. + +With a single key the stored estimate is returned. With several keys the structures are merged on the fly and the cardinality of their union is returned, without modifying any of them, which is how you answer "how many unique users across these seven days" without double counting. The result is an approximation with a standard error of about 0.81%. + +The multi-key form does real work on every call, so when the same union is read often it is cheaper to roll the sources up into one key with [`PFMERGE`](/docs/redis/commands/hyperloglog/pfmerge) and count that. + +## Syntax + +```redis +PFCOUNT [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | Yes | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PFCOUNT my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.pfcount("my-key"); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.pfcount("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.pfcount("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.pfCount("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.pfcount("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.PFCount(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.pfcount("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.pfcount(&["my-key"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# PFMERGE +Source: https://upstash.com/docs/redis/commands/hyperloglog/pfmerge + +Use `PFMERGE` to merge several HyperLogLogs into a single one. + +The destination ends up representing the union of the source structures and of whatever it already held, so merging the same sources again changes nothing and new data can be folded in as it arrives. The destination is created if it does not exist. + +Because the union is computed register by register and loses no accuracy compared with counting the raw data, rolling hourly keys into a daily key, or daily keys into a monthly one, gives the same estimate as if every element had been added to that key directly. That makes `PFMERGE` the building block for time-based rollups of unique counts. + +## Syntax + +```redis +PFMERGE [ [ ...]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key used as destkey. | +| `` | No | Yes | Redis key used as sourcekey. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PFMERGE destination-key source-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.pfmerge("destination-key", "source-key"); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.pfmerge("destination-key", "source-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.pfmerge("destination-key", "source-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.pfMerge("destination-key", "source-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.pfmerge("destination-key", "source-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.PFMerge(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.pfmerge("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.pfmerge("destination-key", &["source-key"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.ARRAPPEND +Source: https://upstash.com/docs/redis/commands/json/json-arrappend + +Use `JSON.ARRAPPEND` to append one or more values to the end of the arrays a path selects. + +Values are JSON text and each one is appended as a single element, so appending an array adds a nested array rather than merging its items. The reply is the new length of each array the path matched, with null for matches that are not arrays. + +## Syntax + +```redis +JSON.ARRAPPEND [value ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | Yes | No | Path selecting arrays. | +| `value` | Yes | Yes | Valid JSON value to append. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer lengths or null values, one per matched path | +| RESP3 | Array of integer lengths or null values, one per matched path | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.ARRAPPEND profile $.tags '"new"' +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.json.arrappend("key", "$.path.to.array", "a"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().arrappend("profile", "$.tags", "new") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.ARRAPPEND", "profile", "$.tags", "\"new\""); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.arrAppend("profile", "$.tags", "new"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().arrappend("profile", "$.tags", "new") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONArrAppend(context.Background(), "profile", "$.tags", "new").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonArrAppend("profile", new redis.clients.jedis.json.Path("$.tags"), "new"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_arr_append("profile", "$.tags", &"new")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.ARRINDEX +Source: https://upstash.com/docs/redis/commands/json/json-arrindex + +Use `JSON.ARRINDEX` to find the first position of a value inside the arrays a path selects. + +The value is JSON text and is compared for exact equality, so `1` does not match `"1"`. The optional `start` and `stop` bound the search: `start` is inclusive, `stop` is exclusive, both may be negative to count from the end of the array, and `0` for `stop` means "to the end". The reply is the index of the first match or `-1` when the value is not present, with one result per array the path matched. + +## Syntax + +```redis +JSON.ARRINDEX [start [stop]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | Yes | No | Path selecting arrays. | +| `value` | Yes | No | Valid JSON value to locate. | +| `start` | No | No | Inclusive starting index. | +| `stop` | No | No | Exclusive ending index. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer indexes or null values, one per matched path | +| RESP3 | Array of integer indexes or null values, one per matched path | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.ARRINDEX profile $.tags '"new"' +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const index = await redis.json.arrindex("key", "$.path.to.array", "a"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().arrindex("profile", "$.tags", "new") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.ARRINDEX", "profile", "$.tags", "\"new\""); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.arrIndex("profile", "$.tags", "new"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().arrindex("profile", "$.tags", "new") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONArrIndex(context.Background(), "profile", "$.tags", "new").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonArrIndex("profile", new redis.clients.jedis.json.Path("$.tags"), "new"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_arr_index("profile", "$.tags", &"new")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.ARRINSERT +Source: https://upstash.com/docs/redis/commands/json/json-arrinsert + +Use `JSON.ARRINSERT` to insert one or more values into the arrays a path selects, before a given index. + +Elements at and after that index shift to the right, keeping the rest of the array in order. A negative index counts from the end of the array and an index equal to the array's length appends, while an index outside the array returns an error. The reply is the new length of each array the path matched. + +## Syntax + +```redis +JSON.ARRINSERT [value ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | Yes | No | Path selecting arrays. | +| `index` | Yes | No | Insertion index; negative indexes count from the end. | +| `value` | Yes | Yes | Valid JSON value to insert. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer lengths or null values, one per matched path | +| RESP3 | Array of integer lengths or null values, one per matched path | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.ARRINSERT profile $.tags 0 '"first"' +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const length = await redis.json.arrinsert("key", "$.path.to.array", 2, "a", "b"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().arrinsert("profile", "$.tags", 0, "first") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.ARRINSERT", "profile", "$.tags", "0", "\"first\""); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.arrInsert("profile", "$.tags", 0, "first"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().arrinsert("profile", "$.tags", 0, "first") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONArrInsert(context.Background(), "profile", "$.tags", 0, "first").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonArrInsert("profile", new redis.clients.jedis.json.Path("$.tags"), 0, "first"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_arr_insert("profile", "$.tags", 0, &"first")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.ARRLEN +Source: https://upstash.com/docs/redis/commands/json/json-arrlen + +Use `JSON.ARRLEN` to get the number of elements in the arrays a path selects. + +Without a path the root value is used. The reply is one length per match, with null for matches that are not arrays, so it doubles as a cheap way to check that a branch of the document really is an array before working on it. + +## Syntax + +```redis +JSON.ARRLEN [path] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | No | No | Path selecting arrays; defaults to the root. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer lengths or null values, one per matched path | +| RESP3 | Array of integer lengths or null values, one per matched path | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.ARRLEN profile $.tags +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const length = await redis.json.arrlen("key", "$.path.to.array"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().arrlen("profile", "$.tags") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.ARRLEN", "profile", "$.tags"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.arrLen("profile", { path: "$.tags" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().arrlen("profile", "$.tags") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONArrLen(context.Background(), "profile", "$.tags").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonArrLen("profile", new redis.clients.jedis.json.Path("$.tags")); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_arr_len("profile", "$.tags")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.ARRPOP +Source: https://upstash.com/docs/redis/commands/json/json-arrpop + +Use `JSON.ARRPOP` to remove an element from the arrays a path selects and return it. + +Without an index the last element is popped, which makes the command a stack pop; index `0` pops the first element, and negative indexes count from the end. An index past the end of the array is clamped to the last element. The reply is the removed element as JSON text, or null when the array is empty. + +Because the read and the removal happen in one atomic step, a JSON array can be used as a small work queue without the risk of two clients taking the same element. + +## Syntax + +```redis +JSON.ARRPOP [path [index]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | No | No | Path selecting arrays; defaults to the root. | +| `index` | No | No | Element index; defaults to the last element. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string JSON values or null values, one per matched path | +| RESP3 | Array of bulk-string JSON values or null values, one per matched path | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.ARRPOP profile $.tags -1 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const element = await redis.json.arrpop("key", "$.path.to.array"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().arrpop("profile", "$.tags", -1) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.ARRPOP", "profile", "$.tags", "-1"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.arrPop("profile", { path: "$.tags", index: -1 }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().arrpop("profile", "$.tags", -1) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONArrPop(context.Background(), "profile", "$.tags", -1).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonArrPop("profile", new redis.clients.jedis.json.Path("$.tags"), -1); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_arr_pop("profile", "$.tags", -1)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.ARRTRIM +Source: https://upstash.com/docs/redis/commands/json/json-arrtrim + +Use `JSON.ARRTRIM` to keep only a range of elements in the arrays a path selects and discard the rest. + +Both `start` and `stop` are inclusive indexes and may be negative to count from the end of the array. Indexes outside the array are clamped, and a range that selects nothing leaves an empty array. The reply is the new length of each array the path matched. + +It is the JSON counterpart of [`LTRIM`](/docs/redis/commands/list/ltrim): combine it with [`JSON.ARRAPPEND`](/docs/redis/commands/json/json-arrappend) to keep a capped list, such as the last N events, inside a document. + +## Syntax + +```redis +JSON.ARRTRIM +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | Yes | No | Path selecting arrays. | +| `start` | Yes | No | Inclusive first index to keep. | +| `stop` | Yes | No | Inclusive last index to keep. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer lengths or null values, one per matched path | +| RESP3 | Array of integer lengths or null values, one per matched path | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.ARRTRIM profile $.tags 0 9 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const length = await redis.json.arrtrim("key", "$.path.to.array", 2, 10); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().arrtrim("profile", "$.tags", 0, 9) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.ARRTRIM", "profile", "$.tags", "0", "9"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.arrTrim("profile", "$.tags", 0, 9); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().arrtrim("profile", "$.tags", 0, 9) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONArrTrimWithArgs(context.Background(), "profile", "$.tags", &redis.JSONArrTrimArgs{Start: 0, Stop: func() *int { stop := 9; return &stop }()}).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonArrTrim("profile", new redis.clients.jedis.json.Path("$.tags"), 0, 9); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_arr_trim("profile", "$.tags", 0, 9)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.CLEAR +Source: https://upstash.com/docs/redis/commands/json/json-clear + +Use `JSON.CLEAR` to empty the values a path selects without removing them from the document. + +Objects lose all their keys, arrays lose all their elements, and numbers are reset to `0`. Values of other types, such as strings and booleans, are left as they are. The reply is the number of values that were cleared. + +The difference from [`JSON.DEL`](/docs/redis/commands/json/json-del) is that the selected keys and slots stay in the document as empty containers, so the shape of the document is preserved and consumers that expect a field to exist keep working. + +## Syntax + +```redis +JSON.CLEAR [path] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | No | No | Path to containers or numbers; defaults to the root. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.CLEAR profile $.stats +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.json.clear("key"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().clear("profile", "$.stats") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.CLEAR", "profile", "$.stats"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.clear("profile", { path: "$.stats" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().clear("profile", "$.stats") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONClear(context.Background(), "profile", "$.stats").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonClear("profile", new redis.clients.jedis.json.Path("$.stats")); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_clear("profile", "$.stats")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.DEBUG +Source: https://upstash.com/docs/redis/commands/json/json-debug + +Use `JSON.DEBUG` to inspect internal details of stored JSON values. + +`JSON.DEBUG MEMORY` reports the approximate number of bytes used by the value a key and optional path select, which is how you find out which documents, or which branches of a document, are responsible for memory growth. The figure includes internal overhead and is an estimate meant for comparison rather than exact accounting. `JSON.DEBUG HELP` lists the supported forms. + +It is a diagnostic aid: the details it exposes are implementation-specific and can change, so do not build application logic on them. + +## Syntax + +```redis +JSON.DEBUG MEMORY [path] +JSON.DEBUG HELP +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `MEMORY` | One form | No | Report the approximate memory used by the JSON value selected by key and optional path. | +| `key` | For MEMORY | No | JSON document key. | +| `path` | No | No | JSONPath to inspect; defaults to the root. | +| `HELP` | One form | No | Return the supported JSON.DEBUG forms. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer, array of integers, or array of help strings | +| RESP3 | Integer, array of integers, or array of help strings | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.DEBUG MEMORY profile $.stats +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.DEBUG", "MEMORY", "profile", "$.stats"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.debugMemory("profile", { path: "$.stats" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().debug("MEMORY", "profile", "$.stats") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONDebugMemory(context.Background(), "profile", "$.stats").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonDebugMemory("profile", new redis.clients.jedis.json.Path("$.stats")); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("JSON.DEBUG"); + command.arg("MEMORY"); + command.arg("profile"); + command.arg("$.stats"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.DEL +Source: https://upstash.com/docs/redis/commands/json/json-del + +Use `JSON.DEL` to delete the value at a path in a JSON document. + +Without a path the entire key is deleted. The reply is the number of values that were deleted, which is `0` when the path matched nothing, and deleting the root of a document removes the key itself. With a JSONPath that matches several places, every match is removed in the same call. + +[`JSON.FORGET`](/docs/redis/commands/json/json-forget) is an alias with identical behavior. + +## Syntax + +```redis +JSON.DEL [path] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | No | No | Path to delete; omitting it deletes the whole key. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.DEL profile $.temporary +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.json.del("key", "$.path.to.value"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().delete("profile", "$.temporary") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.DEL", "profile", "$.temporary"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.del("profile", { path: "$.temporary" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().delete("profile", "$.temporary") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONDel(context.Background(), "profile", "$.temporary").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonDel("profile", new redis.clients.jedis.json.Path("$.temporary")); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_del("profile", "$.temporary")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.FORGET +Source: https://upstash.com/docs/redis/commands/json/json-forget + +Use `JSON.FORGET` to delete the value at a path in a JSON document. It is an alias of [`JSON.DEL`](/docs/redis/commands/json/json-del) with identical behavior, kept for compatibility with clients and code that use the older name. + +Without a path the entire key is deleted, and the reply is the number of values that were deleted, which is `0` when the path matched nothing. + +## Syntax + +```redis +JSON.FORGET [path] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | No | No | Path to delete; omitting it deletes the whole key. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.FORGET profile $.temporary +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.json.forget("key", "$.path.to.value"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().forget("profile", "$.temporary") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.FORGET", "profile", "$.temporary"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.forget("profile", { path: "$.temporary" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().forget("profile", "$.temporary") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONForget(context.Background(), "profile", "$.temporary").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonDel("profile", new redis.clients.jedis.json.Path("$.temporary")); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_del("profile", "$.temporary")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.GET +Source: https://upstash.com/docs/redis/commands/json/json-get + +Use `JSON.GET` to read one or more values from a JSON document. + +Without a path the whole document is returned. The reply shape depends on the path syntax: a path starting with `$` is a JSONPath and always returns an array with one entry per match, so an empty array means nothing matched, while the legacy dot syntax returns the value itself and reports an error when the path does not exist. Passing several paths returns an object keyed by the path expressions, which is a cheap way to pull a few unrelated branches of a large document in one call. + +`INDENT`, `NEWLINE`, and `SPACE` control the formatting of the returned JSON text, which is otherwise compact. They are meant for human-readable output; leave them out when a program parses the reply. + +## Syntax + +```redis +JSON.GET + [INDENT indent] + [NEWLINE newline] + [SPACE space] + [path [path ...]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `INDENT indent` | No | No | Indentation characters for formatted JSON. | +| `NEWLINE newline` | No | No | Line-separator characters for formatted JSON. | +| `SPACE space` | No | No | Characters placed after JSON separators. | +| `path` | No | Yes | One or more paths; defaults to the root. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string or Null bulk string or null array | +| RESP3 | Bulk string or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.GET profile $.name +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const value = await redis.json.get("key", "$.path.to.somewhere"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().get("profile", "$.name") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.GET", "profile", "$.name"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.get("profile", { path: "$.name" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().get("profile", "$.name") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONGet(context.Background(), "profile", "$.name").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonGet("profile", new redis.clients.jedis.json.Path("$.name")); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_get("profile", &["$.name"])?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.MERGE +Source: https://upstash.com/docs/redis/commands/json/json-merge + +Use `JSON.MERGE` to merge a JSON value into a document at a path, following the JSON Merge Patch semantics of RFC 7386. + +Objects are merged recursively: keys in the patch replace or create the matching keys in the target, keys set to `null` delete them, and any value that is not an object, arrays included, replaces the target outright instead of being merged element by element. The parent must already exist: merging into a missing child of an existing object creates it, but intermediate levels are not built along the way, and a key that does not exist yet can only be created by merging at the root. + +This is the command for partial updates of an object, where [`JSON.SET`](/docs/redis/commands/json/json-set) would replace the whole branch: one call can change a few fields, delete another, and leave the rest of the document untouched. + +## Syntax + +```redis +JSON.MERGE +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | Yes | No | Path to merge into. | +| `value` | Yes | No | Valid JSON value containing the merge patch. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.MERGE profile $ '{"active":true}' +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.json.merge("key", "$.path.to.value", {"new": "value"}) +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().merge("profile", "$", {"active": True}) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.MERGE", "profile", "$", "{\"active\":true}"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.merge("profile", "$", { active: true }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().merge("profile", "$", {"active": True}) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONMerge(context.Background(), "profile", "$", `{"active":true}`).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonMerge("profile", new redis.clients.jedis.json.Path("$"), java.util.Map.of("active", true)); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("JSON.MERGE"); + command.arg("profile"); + command.arg("$"); + command.arg("{\"active\":true}"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.MGET +Source: https://upstash.com/docs/redis/commands/json/json-mget + +Use `JSON.MGET` to read the same path from several JSON documents in one call. + +The reply holds one entry per key, in the order requested, containing what the path selected in that document, or null when the key does not exist or the path matches nothing. It replaces one [`JSON.GET`](/docs/redis/commands/json/json-get) per key when you are gathering the same field across many documents, for example the price of every product in a cart. + +## Syntax + +```redis +JSON.MGET [key ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | Yes | One or more JSON document keys. | +| `path` | Yes | No | Path read from every key. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string JSON values or null values, one per key | +| RESP3 | Array of bulk-string JSON values or null values, one per key | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.MGET profile:1 profile:2 $.name +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const values = await redis.json.mget(["key1", "key2"], "$.path.to.somewhere"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().mget(["profile:1", "profile:2"], "$.name") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.MGET", "profile:1", "profile:2", "$.name"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.mGet(["profile:1", "profile:2"], "$.name"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().mget(["profile:1", "profile:2"], "$.name") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONMGet(context.Background(), "$.name", "profile:1", "profile:2").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonMGet(new redis.clients.jedis.json.Path2("$.name"), "profile:1", "profile:2"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_mget(&["profile:1", "profile:2"], "$.name")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.MSET +Source: https://upstash.com/docs/redis/commands/json/json-mset + +Use `JSON.MSET` to set values at paths in several JSON documents in one atomic call. + +Each triple gives a key, a path, and a value, and missing keys are created. Either every write is applied or none is, with no other command running in between, which is what makes it the right tool for documents that must stay consistent with each other. The reply is `OK`. + +## Syntax + +```redis +JSON.MSET [key path value ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key path value` | Yes | Yes | One or more key, path, and valid-JSON-value triples. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.MSET profile:1 $ '{"name":"Ada"}' +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.json.mset([ + { key: "profile:1", path: "$", value: { name: "Ada" } }, +]); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().mset([("profile:1", "$", {"name": "Ada"})]) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.MSET", "profile:1", "$", "{\"name\":\"Ada\"}"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.mSet([{ key: "profile:1", path: "$", value: { name: "Ada" } }]); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().mset([("profile:1", "$", {"name": "Ada"})]) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONMSet(context.Background(), "profile:1", "$", `{"name":"Ada"}`).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; +import java.nio.charset.StandardCharsets; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.commands.ProtocolCommand; + +ProtocolCommand command = () -> "JSON.MSET".getBytes(StandardCharsets.UTF_8); +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.sendCommand(command, "profile:1", "$", "{\"name\":\"Ada\"}"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("JSON.MSET"); + command.arg("profile:1"); + command.arg("$"); + command.arg("{\"name\":\"Ada\"}"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.NUMINCRBY +Source: https://upstash.com/docs/redis/commands/json/json-numincrby + +Use `JSON.NUMINCRBY` to add a number to the numeric values a path selects. + +The increment may be negative to count down, and it is applied atomically, so concurrent callers cannot lose an update. The reply is the new value of each match; a match that is not a number returns an error. This is how a counter kept inside a document is updated without reading and rewriting the whole document. + +## Syntax + +```redis +JSON.NUMINCRBY +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | Yes | No | Path selecting numbers. | +| `value` | Yes | No | Numeric amount to add. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string containing a JSON number or array | +| RESP3 | Bulk string containing a JSON number or array | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.NUMINCRBY profile $.visits 1 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const newValue = await redis.json.numincrby("key", "$.path.to.value", 2); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().numincrby("profile", "$.visits", 1) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.NUMINCRBY", "profile", "$.visits", "1"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.numIncrBy("profile", "$.visits", 1); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().numincrby("profile", "$.visits", 1) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONNumIncrBy(context.Background(), "profile", "$.visits", 1).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonNumIncrBy("profile", new redis.clients.jedis.json.Path("$.visits"), 1); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_num_incr_by("profile", "$.visits", 1)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.NUMMULTBY +Source: https://upstash.com/docs/redis/commands/json/json-nummultby + +Use `JSON.NUMMULTBY` to multiply the numeric values a path selects by a number. + +The multiplier may be a fraction to scale values down, and the update is atomic. The reply is the new value of each match, and a match that is not a number returns an error. It is the multiplicative counterpart of [`JSON.NUMINCRBY`](/docs/redis/commands/json/json-numincrby), useful for applying percentage changes such as a discount to every price in a document. + +## Syntax + +```redis +JSON.NUMMULTBY +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | Yes | No | Path selecting numbers. | +| `value` | Yes | No | Numeric multiplier. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string containing a JSON number or array | +| RESP3 | Bulk string containing a JSON number or array | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.NUMMULTBY profile $.score 2 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const newValue = await redis.json.nummultby("key", "$.path.to.value", 2); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().nummultby("profile", "$.score", 2) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.NUMMULTBY", "profile", "$.score", "2"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.numMultBy("profile", "$.score", 2); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().nummultby("profile", "$.score", 2) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Do(context.Background(), "JSON.NUMMULTBY", "profile", "$.score", "2").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; +import java.nio.charset.StandardCharsets; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.commands.ProtocolCommand; + +ProtocolCommand command = () -> "JSON.NUMMULTBY".getBytes(StandardCharsets.UTF_8); +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.sendCommand(command, "profile", "$.score", "2"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("JSON.NUMMULTBY"); + command.arg("profile"); + command.arg("$.score"); + command.arg("2"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.OBJKEYS +Source: https://upstash.com/docs/redis/commands/json/json-objkeys + +Use `JSON.OBJKEYS` to list the field names of the objects a path selects. + +Without a path the root value is used. The reply holds one list of keys per match, with null for matches that are not objects. Only the field names come back, not the values, which makes it a cheap way to inspect the shape of a document before reading it. + +## Syntax + +```redis +JSON.OBJKEYS [path] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | No | No | Path selecting objects; defaults to the root. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of arrays of bulk-string object keys or null values, or Null bulk string or null array | +| RESP3 | Array of arrays of bulk-string object keys or null values, or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.OBJKEYS profile $ +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const keys = await redis.json.objkeys("key", "$.path"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().objkeys("profile", "$") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.OBJKEYS", "profile", "$"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.objKeys("profile", { path: "$" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().objkeys("profile", "$") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONObjKeys(context.Background(), "profile", "$").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonObjKeys("profile", new redis.clients.jedis.json.Path("$")); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_obj_keys("profile", "$")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.OBJLEN +Source: https://upstash.com/docs/redis/commands/json/json-objlen + +Use `JSON.OBJLEN` to get the number of fields in the objects a path selects. + +Without a path the root value is used. The reply holds one count per match, with null for matches that are not objects. It counts only the object's own fields, not the fields of nested objects. + +## Syntax + +```redis +JSON.OBJLEN [path] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | No | No | Path selecting objects; defaults to the root. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer, array of integer lengths or null values, or Null bulk string or null array | +| RESP3 | Integer, array of integer lengths or null values, or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.OBJLEN profile $ +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const lengths = await redis.json.objlen("key", "$.path"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().objlen("profile", "$") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.OBJLEN", "profile", "$"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.objLen("profile", { path: "$" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().objlen("profile", "$") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONObjLen(context.Background(), "profile", "$").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonObjLen("profile", new redis.clients.jedis.json.Path("$")); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_obj_len("profile", "$")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.RESP +Source: https://upstash.com/docs/redis/commands/json/json-resp + +Use `JSON.RESP` to get a JSON value in RESP form instead of as JSON text. + +The document is translated structurally: an object becomes an array whose first element is `{` followed by alternating field names and values, an array becomes an array whose first element is `[` followed by its elements, and scalars become the corresponding RESP types. Nested values are translated the same way, recursively. + +This lets a client walk the structure using the protocol types it already decodes, without running a JSON parser on the reply. For ordinary use, [`JSON.GET`](/docs/redis/commands/json/json-get) is the more convenient command. + +## Syntax + +```redis +JSON.RESP [path] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | No | No | Path to convert; defaults to the root. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Nested array, Integer, Bulk string, Simple string (`true` or `false` for JSON booleans), or Null bulk string or null array | +| RESP3 | Nested array, Integer, Bulk string, Simple string (`true` or `false` for JSON booleans), or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.RESP profile $ +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.json.resp("profile", "$"); +console.log(result); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().resp("profile", "$") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.RESP", "profile", "$"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.sendCommand(["JSON.RESP", "profile", "$"]); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().resp("profile", "$") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Do(context.Background(), "JSON.RESP", "profile", "$").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; +import java.nio.charset.StandardCharsets; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.commands.ProtocolCommand; + +ProtocolCommand command = () -> "JSON.RESP".getBytes(StandardCharsets.UTF_8); +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.sendCommand(command, "profile", "$"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("JSON.RESP"); + command.arg("profile"); + command.arg("$"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.SET +Source: https://upstash.com/docs/redis/commands/json/json-set + +Use `JSON.SET` to set a JSON value at a path inside a document, creating the key when it does not exist. + +The value is JSON text; the Upstash SDK helpers serialize native objects for you. With the root path (`$`) the whole document is replaced, which is also how a new document is created. For a nested path the parent must already exist: the command adds one missing child to an existing object or appends to an existing array, but it does not create intermediate levels along the way. + +`NX` writes only when the path does not exist yet and `XX` only when it does, which makes conditional updates atomic. When the path is a JSONPath that matches several places, every match is updated in the same call, so a single command can update all elements of an array. + +## Syntax + +```redis +JSON.SET [NX | XX] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | Yes | No | Path to create or replace. | +| `value` | Yes | No | Valid JSON value. | +| `NX \| XX` | No | No | Write only when the path is absent (`NX`) or present (`XX`). | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK`, or Null bulk string or null array when `NX` or `XX` prevented the write | +| RESP3 | Simple string `OK`, or Null when `NX` or `XX` prevented the write | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.SET profile $ '{"name":"Ada"}' +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +redis.json.set(key, "$.path", value); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().set("profile", "$", {"name": "Ada"}) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.SET", "profile", "$", "{\"name\":\"Ada\"}"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.set("profile", "$", { name: "Ada" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().set("profile", "$", {"name": "Ada"}) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONSet(context.Background(), "profile", "$", map[string]interface{}{"name": "Ada"}).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonSet("profile", new redis.clients.jedis.json.Path("$"), java.util.Map.of("name", "Ada")); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_set("profile", "$", &serde_json::json!({"name": "Ada"}))?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.STRAPPEND +Source: https://upstash.com/docs/redis/commands/json/json-strappend + +Use `JSON.STRAPPEND` to append text to the string values a path selects. + +The value is JSON text, so the appended string must be quoted, as in `'"suffix"'`. The reply is the new length of each string the path matched, with an error for matches that are not strings. Appending in place avoids reading and rewriting the whole document just to extend one field. + +## Syntax + +```redis +JSON.STRAPPEND +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | Yes | No | Path selecting strings. | +| `value` | Yes | No | JSON-encoded string to append. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer, array of integer lengths or null values, or Null bulk string or null array | +| RESP3 | Integer, array of integer lengths or null values, or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.STRAPPEND profile $.name '" Lovelace"' +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.json.strappend("key", "$.path.to.str", "abc"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().strappend("profile", "$.name", " Lovelace") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.STRAPPEND", "profile", "$.name", "\" Lovelace\""); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.strAppend("profile", " Lovelace", { path: "$.name" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().strappend("profile", " Lovelace", "$.name") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONStrAppend(context.Background(), "profile", "$.name", `" Lovelace"`).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonStrAppend("profile", new redis.clients.jedis.json.Path("$.name"), " Lovelace"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_str_append("profile", "$.name", " Lovelace")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.STRLEN +Source: https://upstash.com/docs/redis/commands/json/json-strlen + +Use `JSON.STRLEN` to get the length of the string values a path selects. + +Without a path the root value is used. The reply holds one length per match, with null for matches that are not strings, so it is also a quick way to check that a field is a string. The value itself is not transferred, which makes it cheap even for long strings. + +## Syntax + +```redis +JSON.STRLEN [path] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | No | No | Path selecting strings; defaults to the root. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer, array of integer lengths or null values, or Null bulk string or null array | +| RESP3 | Integer, array of integer lengths or null values, or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.STRLEN profile $.name +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.json.strlen("key", "$.path.to.str", "a"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().strlen("profile", "$.name") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.STRLEN", "profile", "$.name"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.strLen("profile", { path: "$.name" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().strlen("profile", "$.name") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONStrLen(context.Background(), "profile", "$.name").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonStrLen("profile", new redis.clients.jedis.json.Path("$.name")); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_str_len("profile", "$.name")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.TOGGLE +Source: https://upstash.com/docs/redis/commands/json/json-toggle + +Use `JSON.TOGGLE` to flip the boolean values a path selects, turning `true` into `false` and back. + +The reply is the new value of each match, and a match that is not a boolean returns an error. Because the read and the write are one atomic step, this is the safe way to flip a flag inside a document, where reading it and writing the opposite value back would race with other clients. + +## Syntax + +```redis +JSON.TOGGLE +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | Yes | No | Path selecting Boolean values. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of integer Boolean values or null values, one per matched path | +| RESP3 | Array of integer Boolean values or null values, one per matched path | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.TOGGLE profile $.active +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const bool = await redis.json.toggle("key", "$.path.to.bool"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().toggle("profile", "$.active") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.TOGGLE", "profile", "$.active"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.toggle("profile", "$.active"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().toggle("profile", "$.active") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONToggle(context.Background(), "profile", "$.active").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonToggle("profile", new redis.clients.jedis.json.Path("$.active")); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_toggle("profile", "$.active")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON.TYPE +Source: https://upstash.com/docs/redis/commands/json/json-type + +Use `JSON.TYPE` to find out the JSON type of the values a path selects. + +The reply names one type per match, one of `object`, `array`, `string`, `integer`, `number`, `boolean`, or `null`, and is empty when the path matches nothing. Whole numbers report as `integer` and fractional ones as `number`. It is the way to inspect documents whose shape you do not control before applying type-specific commands, which would otherwise fail. + +## Syntax + +```redis +JSON.TYPE [path] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `key` | Yes | No | JSON document key. | +| `path` | No | No | Path to inspect; defaults to the root. | + +## Important points + +* Raw TCP examples pass JSON values as valid JSON text. Typed Upstash SDK helpers serialize native objects and values for you. +* Paths beginning with `$` use JSONPath and can match multiple values, so many JSON commands return an array of per-match results. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string, array of bulk-string type names, or Null bulk string or null array | +| RESP3 | Bulk string, array of bulk-string type names, or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +JSON.TYPE profile $.name +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const myType = await redis.json.type("key", "$.path.to.value"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.json().type("profile", "$.name") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.call("JSON.TYPE", "profile", "$.name"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.json.type("profile", { path: "$.name" }); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.json().type("profile", "$.name") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.JSONType(context.Background(), "profile", "$.name").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.JedisPooled; + +try (JedisPooled jedis = new JedisPooled(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.jsonType("profile", new redis.clients.jedis.json.Path("$.name")); + System.out.println(result); +} +``` + + + + + +```rust +use redis::JsonCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: redis::Value = connection.json_type("profile", "$.name")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# JSON commands +Source: https://upstash.com/docs/redis/commands/json/overview + +To query inside JSON values (full-text, fuzzy, phrase, regex), see [Upstash Redis Search](/docs/redis/search/introduction). + + +Append values to JSON array +Find index of value in array +Insert values into JSON array +Get JSON array length +Pop value from JSON array +Trim JSON array to range +Clear JSON values +Delete JSON values +Inspect JSON memory usage +Delete JSON values (alias of JSON.DEL) +Get JSON values +Merge JSON values +Get values from multiple keys +Set values in multiple keys +Increment JSON number +Multiply JSON number +Get JSON object keys +Get JSON object size +Get JSON in RESP format +Set JSON value +Append to JSON string +Get JSON string length +Toggle JSON boolean +Get JSON value type + + +# BLMOVE +Source: https://upstash.com/docs/redis/commands/list/blmove + +Use `BLMOVE` to move an element from one list to another, blocking until the source has an element or the timeout expires. + +It is the blocking form of [`LMOVE`](/docs/redis/commands/list/lmove): when the source list is not empty it behaves identically and returns immediately, and when it is empty the connection waits instead of returning null. The timeout is given in seconds, may be fractional, and `0` waits indefinitely. If several clients are waiting on the same key, the one that has been waiting longest is served first. + +Because the element is never outside a list, this is the standard way to build a reliable queue: a worker blocks until work appears, atomically moves it to a processing list, and deletes it from there when done, so an interrupted job can be recovered instead of lost. + +## Syntax + +```redis +BLMOVE (LEFT | RIGHT) (LEFT | RIGHT) +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key used as source. | +| `` | Yes | No | Redis key used as destination. | +| `(LEFT \| RIGHT)` | Yes | No | Which end of the source list the element is taken from: `LEFT` (head) or `RIGHT` (tail). | +| `(LEFT \| RIGHT)` | Yes | No | Which end of the destination list the element is pushed onto: `LEFT` (head) or `RIGHT` (tail). | +| `` | Yes | No | Seconds to block; `0` blocks indefinitely. | + +## Important points + +* A blocking form holds the request until data arrives or its timeout expires. Set the client/network timeout longer than the command timeout. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string or Null bulk string or null array | +| RESP3 | Bulk string or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +BLMOVE source-key destination-key LEFT LEFT 1.5 +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.blmove("source-key", "destination-key", "LEFT", "LEFT", "1.5"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.blMove("source-key", "destination-key", "LEFT", "LEFT", 1.5); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.blmove("source-key", "destination-key", 1.5, "LEFT", "LEFT") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.BLMove(context.Background(), "source-key", "destination-key", "LEFT", "LEFT", 1500*time.Millisecond).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.blmove("source-key", "destination-key", redis.clients.jedis.args.ListDirection.LEFT, redis.clients.jedis.args.ListDirection.LEFT, 1.5); + System.out.println(result); +} +``` + + + + + +```rust +use redis::{Direction, TypedCommands}; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.blmove( + "source-key", + "destination-key", + Direction::Left, + Direction::Left, + 1.5, + )?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# BLMPOP +Source: https://upstash.com/docs/redis/commands/list/blmpop + +Use `BLMPOP` to pop elements from the first non-empty list among several, blocking until one has elements or the timeout expires. + +It is the blocking form of [`LMPOP`](/docs/redis/commands/list/lmpop): keys are examined in the order given, so listing a high priority queue first drains it before the others are considered, `LEFT` or `RIGHT` chooses the end, and `COUNT` sets how many elements to take. The reply names the key that was popped from along with the elements. + +The timeout is in seconds, may be fractional, and `0` waits indefinitely; when it expires the reply is null. This is the command to reach for when one worker serves several queues of differing priority. + +## Syntax + +```redis +BLMPOP [ ...] (LEFT | RIGHT) [COUNT ] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Seconds to block; `0` blocks indefinitely. | +| `` | Yes | No | Number of key arguments that follow. | +| `` | Yes | Yes | Redis key targeted by the command. | +| `(LEFT \| RIGHT)` | Yes | No | Which end to pop from: `LEFT` (head) or `RIGHT` (tail). | +| `COUNT ` | No | No | Maximum number of elements to pop. | + +## Important points + +* A blocking form holds the request until data arrives or its timeout expires. Set the client/network timeout longer than the command timeout. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Null bulk string or null array, or two-element array: key and array of values | +| RESP3 | Null, or two-element array: key and array of values | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +BLMPOP 1.5 1 my-key LEFT +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.blmpop("1.5", "1", "my-key", "LEFT"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.blmPop(1.5, "my-key", "LEFT"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.blmpop(1.5, 1, "my-key", direction="LEFT") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + _, result, err := client.BLMPop(context.Background(), 1500*time.Millisecond, "LEFT", 0, "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.blmpop(1.5, redis.clients.jedis.args.ListDirection.LEFT, "my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::{Direction, TypedCommands}; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.blmpop(1.5, 1, "my-key", Direction::Left, 1)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# BLPOP +Source: https://upstash.com/docs/redis/commands/list/blpop + +Use `BLPOP` to pop an element from the head of the first non-empty list, blocking until one has an element or the timeout expires. + +It is the blocking form of [`LPOP`](/docs/redis/commands/list/lpop) and it accepts several keys, which are checked in the order given, so earlier keys act as higher priority queues. The reply names the key the element came from together with the element itself, which matters when you are waiting on more than one queue. + +The timeout is in seconds, may be fractional, and `0` waits indefinitely; when it expires the reply is null. Blocking lets a worker wait for work without polling, which cuts both latency and wasted commands. When several clients are blocked on the same key they are served in the order they started waiting. + +## Syntax + +```redis +BLPOP [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | Yes | Redis key targeted by the command. | +| `` | Yes | No | Seconds to block; `0` blocks indefinitely. | + +## Important points + +* A blocking form holds the request until data arrives or its timeout expires. Set the client/network timeout longer than the command timeout. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Null bulk string or null array, or two-element key/value array | +| RESP3 | Null, or two-element key/value array | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +BLPOP my-key 1.5 +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.blpop("my-key", "1.5"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.blPop("my-key", 1.5); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.blpop(["my-key"], timeout=1.5) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.BLPop(context.Background(), 1500*time.Millisecond, "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.blpop(1.5, "my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.blpop("my-key", 1.5)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# BRPOP +Source: https://upstash.com/docs/redis/commands/list/brpop + +Use `BRPOP` to pop an element from the tail of the first non-empty list, blocking until one has an element or the timeout expires. + +It is the blocking form of [`RPOP`](/docs/redis/commands/list/rpop) and behaves like [`BLPOP`](/docs/redis/commands/list/blpop) in every other respect: several keys are checked in the order given, the reply names the key the element came from, the timeout is in seconds and may be fractional with `0` meaning wait forever, and clients blocked on the same key are served in the order they started waiting. + +Producers pushing with [`LPUSH`](/docs/redis/commands/list/lpush) and consumers waiting with `BRPOP` form the classic first-in, first-out worker queue. + +## Syntax + +```redis +BRPOP [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | Yes | Redis key targeted by the command. | +| `` | Yes | No | Seconds to block; `0` blocks indefinitely. | + +## Important points + +* A blocking form holds the request until data arrives or its timeout expires. Set the client/network timeout longer than the command timeout. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Null bulk string or null array, or two-element key/value array | +| RESP3 | Null, or two-element key/value array | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +BRPOP my-key 1.5 +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.brpop("my-key", "1.5"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.brPop("my-key", 1.5); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.brpop(["my-key"], timeout=1.5) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.BRPop(context.Background(), 1500*time.Millisecond, "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.brpop(1.5, "my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.brpop("my-key", 1.5)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# BRPOPLPUSH +Source: https://upstash.com/docs/redis/commands/list/brpoplpush + + + Prefer [`BLMOVE`](/docs/redis/commands/list/blmove) with `RIGHT` and `LEFT` in new code: `BLMOVE RIGHT LEFT `. + + +Use `BRPOPLPUSH` to pop an element from the tail of one list and push it to the head of another, blocking until the source has an element or the timeout expires. + +It is the blocking form of [`RPOPLPUSH`](/docs/redis/commands/list/rpoplpush). The timeout is in seconds, may be fractional, and `0` waits indefinitely; when it expires the reply is null. Since the element moves atomically into the destination, a worker that crashes after taking an item leaves it visible in the processing list, where it can be recovered. + +[`BLMOVE`](/docs/redis/commands/list/blmove) does the same thing and additionally lets you choose which end of each list to use. + +## Syntax + +```redis +BRPOPLPUSH +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key used as source. | +| `` | Yes | No | Redis key used as destination. | +| `` | Yes | No | Seconds to block; `0` blocks indefinitely. | + +## Important points + +* A blocking form holds the request until data arrives or its timeout expires. Set the client/network timeout longer than the command timeout. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string or Null bulk string or null array | +| RESP3 | Bulk string or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +BRPOPLPUSH source-key destination-key 1.5 +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.brpoplpush("source-key", "destination-key", "1.5"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.brPopLPush("source-key", "destination-key", 1.5); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.brpoplpush("source-key", "destination-key", timeout=1.5) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.BRPopLPush(context.Background(), "source-key", "destination-key", 1500*time.Millisecond).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.brpoplpush("source-key", "destination-key", 1); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.brpoplpush("source-key", "destination-key", 1.5)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LINDEX +Source: https://upstash.com/docs/redis/commands/list/lindex + +Use `LINDEX` to read the element at a given position in a list. + +Indexes are zero-based from the head, and negative indexes count from the tail, so `-1` is the last element. The reply is null when the key does not exist or the index is out of range. Redis walks the list from the nearer end to reach the index, so access is fast near the head and tail and gets more expensive towards the middle of a long list. + +## Syntax + +```redis +LINDEX +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Zero-based index; negative values count from the end. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Null bulk string or null array or Bulk string | +| RESP3 | Null or Bulk string | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LINDEX my-key 0 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.rpush("key", "a", "b", "c"); +const element = await redis.lindex("key", 0); +console.log(element); // "a" +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.lindex("my-key", 0) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.lindex("my-key", "0"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lIndex("my-key", 0); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.lindex("my-key", 0) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.LIndex(context.Background(), "my-key", 0).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.lindex("my-key", 0); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.lindex("my-key", 0)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LINSERT +Source: https://upstash.com/docs/redis/commands/list/linsert + +Use `LINSERT` to insert an element immediately before or after another element of a list. + +The pivot is matched by value, and only its first occurrence starting from the head is used. The reply is the new length of the list, `0` when the key does not exist, and `-1` when the pivot value was not found, which is how you tell a failed insert from a successful one. + +Finding the pivot means scanning the list, so this is a linear operation; on long lists it is worth keeping an index elsewhere or using a sorted set instead. + +## Syntax + +```redis +LINSERT (BEFORE | AFTER) +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `(BEFORE \| AFTER)` | Yes | No | Where to place the new element relative to the pivot: `BEFORE` or `AFTER`. | +| `` | Yes | No | Existing element to insert next to. | +| `` | Yes | No | Element to insert. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer: the list length after insertion, `-1` if the pivot was not found, `0` if the key does not exist | +| RESP3 | Integer: the list length after insertion, `-1` if the pivot was not found, `0` if the key does not exist | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LINSERT my-key BEFORE pivot element +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.rpush("key", "a", "b", "c"); +await redis.linsert("key", "before", "b", "x"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.linsert("my-key", "BEFORE", "pivot", "element") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.linsert("my-key", "BEFORE", "pivot", "element"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lInsert("my-key", "BEFORE", "pivot", "element"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.linsert("my-key", "BEFORE", "pivot", "element") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.LInsertBefore(context.Background(), "my-key", "pivot", "element").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.linsert("my-key", redis.clients.jedis.args.ListPosition.BEFORE, "pivot", "element"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.linsert_before("my-key", "pivot", "element")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LLEN +Source: https://upstash.com/docs/redis/commands/list/llen + +Use `LLEN` to get the number of elements in a list. + +The reply is `0` when the key does not exist. The length is maintained by Redis rather than computed on demand, so the command is cheap whatever the size of the list, which makes it the usual way to monitor a queue's backlog. + +## Syntax + +```redis +LLEN +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LLEN my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.rpush("key", "a", "b", "c"); +const length = await redis.llen("key"); +console.log(length); // 3 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.llen("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.llen("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lLen("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.llen("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.LLen(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.llen("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.llen("my-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LMOVE +Source: https://upstash.com/docs/redis/commands/list/lmove + +Use `LMOVE` to atomically take an element from one end of a list and push it onto one end of another list, returning the element. + +The two directions are chosen independently: `LEFT RIGHT` takes from the head of the source and appends to the tail of the destination, which preserves order when transferring between queues, while `LEFT LEFT` behaves like moving between stacks. If the source is empty nothing happens and the reply is null. Source and destination may be the same key, in which case the list is rotated. + +Because the element is never outside a list, `LMOVE` is the building block for reliable queues: a worker moves an item into a processing list, does the work, and removes it from there, so a crash leaves the item recoverable instead of lost. It replaces the deprecated [`RPOPLPUSH`](/docs/redis/commands/list/rpoplpush), and [`BLMOVE`](/docs/redis/commands/list/blmove) is the blocking form. + +## Syntax + +```redis +LMOVE (LEFT | RIGHT) (LEFT | RIGHT) +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key used as source. | +| `` | Yes | No | Redis key used as destination. | +| `(LEFT \| RIGHT)` | Yes | No | Which end of the source list the element is taken from: `LEFT` (head) or `RIGHT` (tail). | +| `(LEFT \| RIGHT)` | Yes | No | Which end of the destination list the element is pushed onto: `LEFT` (head) or `RIGHT` (tail). | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string | +| RESP3 | Bulk string | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LMOVE source-key destination-key LEFT LEFT +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.rpush("source", "a", "b", "c"); +const element = await redis.lmove("source", "destination", "left", "left"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.lmove("source-key", "destination-key", "LEFT", "LEFT") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.lmove("source-key", "destination-key", "LEFT", "LEFT"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lMove("source-key", "destination-key", "LEFT", "LEFT"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.lmove("source-key", "destination-key", "LEFT", "LEFT") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.LMove(context.Background(), "source-key", "destination-key", "LEFT", "LEFT").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.lmove("source-key", "destination-key", redis.clients.jedis.args.ListDirection.LEFT, redis.clients.jedis.args.ListDirection.LEFT); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.lmove("source-key", "destination-key", redis::Direction::Left, redis::Direction::Left)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LMPOP +Source: https://upstash.com/docs/redis/commands/list/lmpop + +Use `LMPOP` to pop elements from the first of several lists that is not empty. + +`` states how many keys follow, `LEFT` or `RIGHT` chooses the end to pop from, and `COUNT` sets how many elements to take, defaulting to one. Keys are examined in the order given and only the first non-empty one is touched, which is exactly what a priority queue needs: list the high priority queue first and it is drained before the others are looked at. + +The reply names the key that was popped from together with the elements, so a caller working with several queues knows where the work came from. When every key is empty the reply is null; use [`BLMPOP`](/docs/redis/commands/list/blmpop) to wait instead. + +## Syntax + +```redis +LMPOP [ ...] (LEFT | RIGHT) [COUNT ] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Number of key arguments that follow. | +| `` | Yes | Yes | Redis key targeted by the command. | +| `(LEFT \| RIGHT)` | Yes | No | Which end to pop from: `LEFT` (head) or `RIGHT` (tail). | +| `COUNT ` | No | No | Maximum number of elements to pop. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Null bulk string or null array, or two-element array: key and array of values | +| RESP3 | Null, or two-element array: key and array of values | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LMPOP 1 my-key LEFT +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); +const result = await redis.lmpop(1, ["my-key"], "LEFT"); +console.log(result); +``` + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.lmpop("1", "my-key", "LEFT"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lmPop("my-key", "LEFT"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.lmpop(1, "my-key", direction="LEFT") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + _, result, err := client.LMPop(context.Background(), "LEFT", 0, "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.lmpop(redis.clients.jedis.args.ListDirection.LEFT, "my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::{Direction, TypedCommands}; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.lmpop(1, "my-key", Direction::Left, 1)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LPOP +Source: https://upstash.com/docs/redis/commands/list/lpop + +Use `LPOP` to remove and return elements from the head of a list. + +Without a count a single element is returned, or null when the key does not exist. With a count, up to that many elements are removed and returned in the order they were popped, and the reply is an empty array or null when the list is empty. The key is deleted once the last element is removed. + +Paired with [`RPUSH`](/docs/redis/commands/list/rpush) this gives a first-in, first-out queue; paired with [`LPUSH`](/docs/redis/commands/list/lpush) it gives a stack. Use [`BLPOP`](/docs/redis/commands/list/blpop) when a consumer should wait for work rather than poll. + +## Syntax + +```redis +LPOP [] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | No | No | Number of elements to pop. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Null bulk string or null array, Bulk string, or array of bulk-string values | +| RESP3 | Null, Bulk string, or array of bulk-string values | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LPOP my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.rpush("key", "a", "b", "c"); +const element = await redis.lpop("key"); +console.log(element); // "a" +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.lpop("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.lpop("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lPop("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.lpop("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.LPop(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.lpop("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: Option = connection.lpop("my-key", None)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LPOS +Source: https://upstash.com/docs/redis/commands/list/lpos + +Use `LPOS` to find the position of an element in a list. + +The scan starts at the head and, by default, reports the index of the first match or null when there is none. `RANK` selects which match to report: `RANK 2` skips to the second occurrence, and a negative rank searches backwards from the tail, so `RANK -1` finds the last occurrence. `COUNT` returns that many matching indexes instead of just one, and `COUNT 0` returns all of them. `MAXLEN` limits how many elements are compared, which bounds the cost of the search on a long list at the price of possibly missing matches beyond that point. + +It is the read-only way to locate a value before acting on it with [`LSET`](/docs/redis/commands/list/lset) or [`LREM`](/docs/redis/commands/list/lrem). + +## Syntax + +```redis +LPOS [RANK ] [COUNT ] [MAXLEN ] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Element value to search for. | +| `RANK ` | No | No | Which match to return; negative values search from the tail. | +| `COUNT ` | No | No | Number of matches to return; `0` returns every match. | +| `MAXLEN ` | No | No | Maximum number of entries to keep in the stream. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Null bulk string or null array, Integer, or array of integer positions | +| RESP3 | Null, Integer, or array of integer positions | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LPOS my-key element +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.rpush("key", "a", "b", "c"); +const index = await redis.lpos("key", "b"); +console.log(index); // 1 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.lpos("my-key", "element") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.lpos("my-key", "element"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lPos("my-key", "element"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.lpos("my-key", "element") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.LPos(context.Background(), "my-key", "element", redis.LPosArgs{}).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.lpos("my-key", "element"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::{LposOptions, TypedCommands}; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: Option = connection.lpos("my-key", "element", LposOptions::default())?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LPUSH +Source: https://upstash.com/docs/redis/commands/list/lpush + +Use `LPUSH` to add one or more elements to the head of a list, creating the list when the key does not exist. + +Elements are inserted one after another, so they end up in reverse order relative to the argument list: `LPUSH key a b c` leaves the list as `c`, `b`, `a`. The reply is the length of the list after the push. If the key holds a value of another type the command returns an error. + +Pushing to the head and popping from the tail with [`RPOP`](/docs/redis/commands/list/rpop) gives a first-in, first-out queue, while popping from the head with [`LPOP`](/docs/redis/commands/list/lpop) gives a stack. Combine with [`LTRIM`](/docs/redis/commands/list/ltrim) to keep a capped list of recent items. + +## Syntax + +```redis +LPUSH [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | Yes | Element to push. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LPUSH my-key element +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const length1 = await redis.lpush("key", "a", "b", "c"); +console.log(length1); // 3 +const length2 = await redis.lpush("key", "d"); +console.log(length2); // 4 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.lpush("my-key", "element") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.lpush("my-key", "element"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lPush("my-key", "element"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.lpush("my-key", "element") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.LPush(context.Background(), "my-key", "element").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.lpush("my-key", "element"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.lpush("my-key", "element")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LPUSHX +Source: https://upstash.com/docs/redis/commands/list/lpushx + +Use `LPUSHX` to add elements to the head of a list only when the list already exists. + +Nothing happens and the reply is `0` when the key does not exist, and no key is created. This is the difference from [`LPUSH`](/docs/redis/commands/list/lpush), and it is what you want when a list should only be fed while a consumer is holding it open, so that stale producers do not resurrect a queue that was already drained and deleted. + +## Syntax + +```redis +LPUSHX [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | Yes | Element to push. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LPUSHX my-key element +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.lpush("key", "a", "b", "c"); +const length = await redis.lpushx("key", "d"); +console.log(length); // 4 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.lpushx("my-key", "element") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.lpushx("my-key", "element"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lPushX("my-key", "element"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.lpushx("my-key", "element") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.LPushX(context.Background(), "my-key", "element").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.lpushx("my-key", "element"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.lpush_exists("my-key", "element")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LRANGE +Source: https://upstash.com/docs/redis/commands/list/lrange + +Use `LRANGE` to read a range of elements from a list. + +Both `` and `` are zero-based, inclusive, and may be negative to count from the tail, so `LRANGE key 0 -1` returns the whole list and `LRANGE key 0 9` returns the first ten elements. Out-of-range indexes are clamped instead of producing an error, and a range that selects nothing, or a missing key, returns an empty list. + +The command copies the requested range into the reply, so reading a large list in one call is expensive: page through it with successive ranges when the list is big. + +## Syntax + +```redis +LRANGE +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Start index; negative values count from the end. | +| `` | Yes | No | Stop index, inclusive; negative values count from the end. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of bulk-string values | +| RESP3 | Array of bulk-string values | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LRANGE my-key 0 0 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.lpush("key", "a", "b", "c"); +const elements = await redis.lrange("key", 1, 2); +console.log(elements) // ["b", "c"] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.lrange("my-key", 0, 0) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.lrange("my-key", "0", "0"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lRange("my-key", 0, 0); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.lrange("my-key", 0, 0) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.LRange(context.Background(), "my-key", 0, 0).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.lrange("my-key", 0, 0); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.lrange("my-key", 0, 0)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LREM +Source: https://upstash.com/docs/redis/commands/list/lrem + +Use `LREM` to remove elements equal to a given value from a list. + +The count decides how many occurrences are removed and in which direction: a positive count removes that many starting from the head, a negative count removes that many starting from the tail, and `0` removes every occurrence. The reply is the number of elements actually removed, and the key is deleted when the list becomes empty. + +Removing by value means scanning the list, so on long lists prefer a set or a sorted set when you frequently need to delete arbitrary items. + +## Syntax + +```redis +LREM +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | How many matches to remove: positive scans head to tail, negative tail to head, `0` removes every match. | +| `` | Yes | No | Element value to remove. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LREM my-key 1 element +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.lpush("key", "a", "a", "b", "b", "c"); +const removed = await redis.lrem("key", 4, "b"); +console.log(removed) // 2 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.lrem("my-key", 1, "element") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.lrem("my-key", "1", "element"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lRem("my-key", 1, "element"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.lrem("my-key", 1, "element") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.LRem(context.Background(), "my-key", 1, "element").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.lrem("my-key", 1, "element"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.lrem("my-key", 1, "element")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LSET +Source: https://upstash.com/docs/redis/commands/list/lset + +Use `LSET` to overwrite the element at a given position in a list. + +Indexes are zero-based from the head and negative indexes count from the tail. The command returns an error when the key does not exist or the index is out of range, since it never grows the list; use [`LPUSH`](/docs/redis/commands/list/lpush) or [`RPUSH`](/docs/redis/commands/list/rpush) to add elements. Locate the position first with [`LPOS`](/docs/redis/commands/list/lpos) when you know the value but not the index. + +## Syntax + +```redis +LSET +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Zero-based index; negative values count from the end. | +| `` | Yes | No | Element to store at the index. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LSET my-key 0 element +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.lpush("key", "a", "b", "c"); +await redis.lset("key", 1, "d"); + +// list is now ["a", "d", "c"] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.lset("my-key", 0, "element") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.lset("my-key", "0", "element"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lSet("my-key", 0, "element"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.lset("my-key", 0, "element") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.LSet(context.Background(), "my-key", 0, "element").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.lset("my-key", 0, "element"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.lset("my-key", 0, "element")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# LTRIM +Source: https://upstash.com/docs/redis/commands/list/ltrim + +Use `LTRIM` to keep only a range of elements in a list and delete everything outside it. + +Both ends are inclusive, zero-based, and may be negative to count from the tail. If `` is greater than `` or lies past the end of the list, every element is removed and the key is deleted. The reply is always `OK`. + +The classic use is a capped list: [`LPUSH`](/docs/redis/commands/list/lpush) a new item and then `LTRIM key 0 99` to keep the hundred most recent ones, which bounds memory without any separate cleanup job. + +## Syntax + +```redis +LTRIM +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | No | Start index; negative values count from the end. | +| `` | Yes | No | Stop index, inclusive; negative values count from the end. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Simple string `OK` | +| RESP3 | Simple string `OK` | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +LTRIM my-key 0 0 +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.lpush("key", "a", "b", "c", "d"); +await redis.ltrim("key", 1, 2); +// the list is now ["b", "c"] +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.ltrim("my-key", 0, 0) +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.ltrim("my-key", "0", "0"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.lTrim("my-key", 0, 0); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.ltrim("my-key", 0, 0) +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.LTrim(context.Background(), "my-key", 0, 0).Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.ltrim("my-key", 0, 0); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.ltrim("my-key", 0, 0)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# List commands +Source: https://upstash.com/docs/redis/commands/list/overview + + +Blocking list move +Blocking pop from multiple lists +Blocking left pop +Blocking right pop +Blocking pop and push +Get element by index +Insert before or after pivot +Get list length +Move element between lists +Pop from the first non-empty list +Pop from list head +Find the position of an element +Push to list head +Push to head if list exists +Get range of elements +Remove elements by value +Set element at index +Trim list to range +Pop from list tail +Pop from tail and push to head +Push to list tail +Push to tail if list exists + + +# RPOP +Source: https://upstash.com/docs/redis/commands/list/rpop + +Use `RPOP` to remove and return elements from the tail of a list. + +Without a count a single element is returned, or null when the key does not exist. With a count, up to that many elements are removed and returned in the order they were popped, and the key is deleted once the last element is gone. + +Combined with [`LPUSH`](/docs/redis/commands/list/lpush) this gives a first-in, first-out queue, since producers add at the head and consumers take from the tail. Use [`BRPOP`](/docs/redis/commands/list/brpop) when a consumer should wait for work instead of polling. + +## Syntax + +```redis +RPOP [] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | No | No | Number of elements to pop. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Null bulk string or null array, Bulk string, or array of bulk-string values | +| RESP3 | Null, Bulk string, or array of bulk-string values | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +RPOP my-key +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.rpush("key", "a", "b", "c"); +const element = await redis.rpop("key"); +console.log(element); // "c" +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.rpop("my-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.rpop("my-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.rPop("my-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.rpop("my-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.RPop(context.Background(), "my-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.rpop("my-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result: Option = connection.rpop("my-key", None)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# RPOPLPUSH +Source: https://upstash.com/docs/redis/commands/list/rpoplpush + + + Prefer [`LMOVE`](/docs/redis/commands/list/lmove) with `RIGHT` and `LEFT` in new code: `LMOVE RIGHT LEFT`. + + +Use `RPOPLPUSH` to atomically move an element from the tail of one list to the head of another, returning the element. + +If the source is empty nothing happens and the reply is null. Source and destination may be the same key, which rotates the list: the tail element becomes the new head, so repeated calls cycle through a list of items forever, a handy pattern for round-robin scheduling. + +[`LMOVE`](/docs/redis/commands/list/lmove) does the same thing but lets you choose both ends, and [`BRPOPLPUSH`](/docs/redis/commands/list/brpoplpush) is the blocking form. + +## Syntax + +```redis +RPOPLPUSH +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key used as source. | +| `` | Yes | No | Redis key used as destination. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Bulk string or Null bulk string or null array | +| RESP3 | Bulk string or Null | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +RPOPLPUSH source-key destination-key +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.rpoplpush("source-key", "destination-key") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.rpoplpush("source-key", "destination-key"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.rPopLPush("source-key", "destination-key"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.rpoplpush("source-key", "destination-key") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.RPopLPush(context.Background(), "source-key", "destination-key").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.rpoplpush("source-key", "destination-key"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.rpoplpush("source-key", "destination-key")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# RPUSH +Source: https://upstash.com/docs/redis/commands/list/rpush + +Use `RPUSH` to add one or more elements to the tail of a list, creating the list when the key does not exist. + +Elements are appended in the order given, so `RPUSH key a b c` leaves the list as `a`, `b`, `c`. The reply is the length of the list after the push, and a key holding another type returns an error. + +Appending with `RPUSH` and consuming from the head with [`LPOP`](/docs/redis/commands/list/lpop) is the standard first-in, first-out queue, and it is the form most job queues use because the natural reading order with [`LRANGE`](/docs/redis/commands/list/lrange) then matches the order of insertion. + +## Syntax + +```redis +RPUSH [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | Yes | Element to push. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +RPUSH my-key element +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const length1 = await redis.rpush("key", "a", "b", "c"); +console.log(length1); // 3 +const length2 = await redis.rpush("key", "d"); +console.log(length2); // 4 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.rpush("my-key", "element") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.rpush("my-key", "element"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.rPush("my-key", "element"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.rpush("my-key", "element") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.RPush(context.Background(), "my-key", "element").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.rpush("my-key", "element"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.rpush("my-key", "element")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# RPUSHX +Source: https://upstash.com/docs/redis/commands/list/rpushx + +Use `RPUSHX` to add elements to the tail of a list only when the list already exists. + +Nothing happens and the reply is `0` when the key does not exist, and no key is created. Use it when producers should append to a queue only while it is alive, for example when the list is created by a consumer that is currently attached, so that writes to a queue nobody is reading do not silently pile up. + +## Syntax + +```redis +RPUSHX [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Redis key targeted by the command. | +| `` | Yes | Yes | Element to push. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +RPUSHX my-key element +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +await redis.lpush("key", "a", "b", "c"); +const length = await redis.rpushx("key", "d"); +console.log(length); // 4 +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.rpushx("my-key", "element") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.rpushx("my-key", "element"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.rPushX("my-key", "element"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.rpushx("my-key", "element") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.RPushX(context.Background(), "my-key", "element").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.rpushx("my-key", "element"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.rpush_exists("my-key", "element")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# Redis command reference +Source: https://upstash.com/docs/redis/commands/overview + +Upstash supports Redis commands over both native Redis TCP and HTTPS REST. Choose a category to browse its supported commands. + + +Manipulate individual bits and bit fields +Authenticate and manage client connections +Load, manage, and invoke Redis functions +Manage keys, expiration, and serialization +Store and query geospatial data +Work with field-value collections +Estimate cardinality +Store and manipulate JSON values +Work with ordered collections +Publish messages and manage subscriptions +Load and execute Lua scripts +Create, query, and manage search indexes +Inspect and manage the Redis server +Work with unique unordered members +Work with scored collections +Process append-only logs and consumer groups +Store and manipulate string values +Group operations into atomic transactions + + +# Pub/Sub commands +Source: https://upstash.com/docs/redis/commands/pub-sub/overview + + +Subscribe to pattern channels +Publish message to channel +Inspect pub/sub state +Unsubscribe from patterns +Subscribe to channels +Unsubscribe from channels + + +# PSUBSCRIBE +Source: https://upstash.com/docs/redis/commands/pub-sub/psubscribe + +Use `PSUBSCRIBE` to subscribe the current connection to channels by glob-style pattern. + +A pattern such as `news.*` matches every channel that starts with `news.`, including channels created after the subscription, which is what makes patterns useful for topic hierarchies. `?` matches a single character and `[...]` a character class. + +Pattern subscriptions are tracked separately from the exact-channel subscriptions made with [`SUBSCRIBE`](/docs/redis/commands/pub-sub/subscribe), and a message that matches several of a connection's patterns is delivered once per matching pattern, so overlapping patterns produce duplicates. Cancel a pattern with [`PUNSUBSCRIBE`](/docs/redis/commands/pub-sub/punsubscribe), passing exactly the same pattern string. + +## Syntax + +```redis +PSUBSCRIBE [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | Yes | Glob-style channel pattern. | + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. +* Subscription commands require a dedicated TCP connection. In RESP3, subscription events use push replies. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Three-element subscription-state array per pattern | +| RESP3 | Three-element subscription-state push reply per pattern | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PSUBSCRIBE events:* +``` + + + + + +```ts +import Redis from "ioredis"; + +const subscriber = new Redis(process.env.REDIS_URL!); +await subscriber.psubscribe("events:*"); +subscriber.on("message", (channel, message) => console.log(channel, message)); +``` + + + + + +```ts +import { createClient } from "redis"; + +const subscriber = await createClient({ url: process.env.REDIS_URL }).connect(); +await subscriber.pSubscribe("events:*", (message, channel) => { + console.log(channel, message); +}); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +pubsub = client.pubsub() +pubsub.psubscribe("events:*") +for message in pubsub.listen(): + print(message) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + ctx := context.Background() + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + pubsub := client.PSubscribe(ctx, "events:*") + for message := range pubsub.Channel() { + fmt.Println(message.Channel, message.Payload) + } +} +``` + + + + + +```java +import java.net.URI; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPubSub; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + jedis.psubscribe(new JedisPubSub() { + @Override + public void onPMessage(String pattern, String channel, String message) { + System.out.println(channel + ": " + message); + } + }, "events:*"); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + let mut pubsub = connection.as_pubsub(); + pubsub.psubscribe("events:*")?; + loop { + let message = pubsub.get_message()?; + let payload: String = message.get_payload()?; + println!("{payload}"); + } + #[allow(unreachable_code)] + Ok(()) +} +``` + + + + + +# PUBLISH +Source: https://upstash.com/docs/redis/commands/pub-sub/publish + +Use `PUBLISH` to send a message to a channel. + +The reply is the number of subscribers the message was delivered to, counting both channel and pattern subscribers, so a reply of `0` means nobody was listening. Delivery is fire and forget: messages are not stored and a client that is not connected at that moment never sees them, so use [streams](/docs/redis/commands/streams/overview) when messages must survive a disconnect or be replayed. + +Publishing works over both the REST API and a TCP connection, while subscribing requires a TCP connection. + +## Syntax + +```redis +PUBLISH +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | No | Channel name. | +| `` | Yes | No | Message payload. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Integer | +| RESP3 | Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PUBLISH events hello +``` + + + + + +```ts +import { Redis } from "@upstash/redis"; + +const redis = Redis.fromEnv(); + +const listeners = await redis.publish("my-channel", "my-message"); +``` + + + + + +```python +from upstash_redis import Redis + +redis = Redis.from_env() +result = redis.publish("events", "hello") +print(result) +``` + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.publish("events", "hello"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.publish("events", "hello"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.publish("events", "hello") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.Publish(context.Background(), "events", "hello").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.publish("events", "hello"); + System.out.println(result); +} +``` + + + + + +```rust +use redis::TypedCommands; + +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let result = connection.publish("events", "hello")?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# PUBSUB +Source: https://upstash.com/docs/redis/commands/pub-sub/pubsub + +Use `PUBSUB` to inspect the state of the pub/sub system without subscribing to anything. + +`CHANNELS` lists the channels that currently have at least one subscriber, optionally filtered by a glob-style pattern. `NUMSUB` reports the subscriber count for each channel you name, and `NUMPAT` reports how many distinct patterns are subscribed to across all clients. + +Only exact-channel subscriptions are counted by `CHANNELS` and `NUMSUB`: a client subscribed with [`PSUBSCRIBE`](/docs/redis/commands/pub-sub/psubscribe) will receive matching messages but does not make a channel appear as active. Use these forms for monitoring and debugging, for instance to confirm that a consumer is really attached before publishing. + +## Syntax + +```redis +PUBSUB CHANNELS [pattern] +PUBSUB NUMSUB [channel ...] +PUBSUB NUMPAT +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `CHANNELS [pattern]` | One form | No | List active channels, optionally filtered by a glob-style pattern. | +| `NUMSUB [channel ...]` | One form | Yes | Return subscriber counts for the supplied channels. | +| `NUMPAT` | One form | No | Return the number of active pattern subscriptions. | + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Array of channel names, flat channel/count array, or Integer | +| RESP3 | Array of channel names, flat channel/count array, or Integer | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PUBSUB CHANNELS events:* +``` + + + + + + + This command is not supported yet in `@upstash/redis`. + + + + + + + + This command is not supported yet in `upstash_redis`. + + + + + + +```ts +import Redis from "ioredis"; + +const redis = new Redis(process.env.REDIS_URL!); +const result = await redis.pubsub("CHANNELS", "events:*"); +console.log(result); +``` + + + + + +```ts +import { createClient } from "redis"; + +const client = await createClient({ url: process.env.REDIS_URL }) + .on("error", console.error) + .connect(); +const result = await client.pubSubChannels("events:*"); +console.log(result); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +result = client.pubsub_channels("events:*") +print(result) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + result, err := client.PubSubChannels(context.Background(), "events:*").Result() + if err != nil { + panic(err) + } + fmt.Println(result) +} +``` + + + + + +```java +import java.net.URI; + +import redis.clients.jedis.Jedis; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + Object result = jedis.pubsubChannels("events:*"); + System.out.println(result); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + + let mut command = redis::cmd("PUBSUB"); + command.arg("CHANNELS"); + command.arg("events:*"); + let result: redis::Value = command.query(&mut connection)?; + println!("{result:?}"); + Ok(()) +} +``` + + + + + +# PUNSUBSCRIBE +Source: https://upstash.com/docs/redis/commands/pub-sub/punsubscribe + +Use `PUNSUBSCRIBE` to cancel pattern subscriptions of the current connection. + +With no arguments the connection unsubscribes from every pattern it registered, otherwise only from the patterns named, which must be given exactly as they were passed to [`PSUBSCRIBE`](/docs/redis/commands/pub-sub/psubscribe), since patterns are matched literally here and not expanded. The server sends one confirmation per pattern with the number of subscriptions still active. + +Exact-channel subscriptions are not affected; cancel those with [`UNSUBSCRIBE`](/docs/redis/commands/pub-sub/unsubscribe). + +## Syntax + +```redis +PUNSUBSCRIBE [ [ ...]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | No | Yes | Glob-style channel pattern; omit to unsubscribe from all patterns. | + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. +* Subscription commands require a dedicated TCP connection. In RESP3, subscription events use push replies. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Three-element subscription-state array per pattern | +| RESP3 | Three-element subscription-state push reply per pattern | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +PUNSUBSCRIBE events:* +``` + + + + + +```ts +import Redis from "ioredis"; + +const subscriber = new Redis(process.env.REDIS_URL!); +await subscriber.psubscribe("events:*"); +await subscriber.punsubscribe("events:*"); +``` + + + + + +```ts +import { createClient } from "redis"; + +const subscriber = await createClient({ url: process.env.REDIS_URL }).connect(); +await subscriber.pSubscribe("events:*", console.log); +await subscriber.pUnsubscribe("events:*"); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +pubsub = client.pubsub() +pubsub.psubscribe("events:*") +pubsub.punsubscribe("events:*") +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + ctx := context.Background() + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + pubsub := client.PSubscribe(ctx, "events:*") + if err := pubsub.PUnsubscribe(ctx, "events:*"); err != nil { + panic(err) + } +} +``` + + + + + +```java +import java.net.URI; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPubSub; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + jedis.psubscribe(new JedisPubSub() { + @Override + public void onPMessage(String pattern, String channel, String message) { + punsubscribe(); + } + }, "events:*"); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + let mut pubsub = connection.as_pubsub(); + pubsub.psubscribe("events:*")?; + pubsub.punsubscribe("events:*")?; + #[allow(unreachable_code)] + Ok(()) +} +``` + + + + + +# SUBSCRIBE +Source: https://upstash.com/docs/redis/commands/pub-sub/subscribe + +Use `SUBSCRIBE` to subscribe the current connection to one or more channels. + +The server confirms each channel with its own reply carrying the running number of subscriptions this connection holds, and from then on messages published to those channels arrive on the connection as they are sent. + +Under RESP2 a subscribed connection may only run subscription commands plus `PING`, `RESET`, and `QUIT`, which is why subscribers normally use a dedicated connection. Under RESP3 messages arrive as push replies and ordinary commands remain usable on the same connection. Messages published while the connection is not subscribed are not delivered later, since pub/sub keeps no history. + +## Syntax + +```redis +SUBSCRIBE [ ...] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | Yes | Yes | Channel name. | + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. +* Subscription commands require a dedicated TCP connection. In RESP3, subscription events use push replies. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Three-element subscription-state array per channel | +| RESP3 | Three-element subscription-state push reply per channel | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +SUBSCRIBE events +``` + + + + + +```ts +import Redis from "ioredis"; + +const subscriber = new Redis(process.env.REDIS_URL!); +await subscriber.subscribe("events"); +subscriber.on("message", (channel, message) => console.log(channel, message)); +``` + + + + + +```ts +import { createClient } from "redis"; + +const subscriber = await createClient({ url: process.env.REDIS_URL }).connect(); +await subscriber.subscribe("events", (message, channel) => { + console.log(channel, message); +}); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +pubsub = client.pubsub() +pubsub.subscribe("events") +for message in pubsub.listen(): + print(message) +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + ctx := context.Background() + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + pubsub := client.Subscribe(ctx, "events") + for message := range pubsub.Channel() { + fmt.Println(message.Channel, message.Payload) + } +} +``` + + + + + +```java +import java.net.URI; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPubSub; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + jedis.subscribe(new JedisPubSub() { + @Override + public void onMessage(String channel, String message) { + System.out.println(channel + ": " + message); + } + }, "events"); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + let mut pubsub = connection.as_pubsub(); + pubsub.subscribe("events")?; + loop { + let message = pubsub.get_message()?; + let payload: String = message.get_payload()?; + println!("{payload}"); + } + #[allow(unreachable_code)] + Ok(()) +} +``` + + + + + +# UNSUBSCRIBE +Source: https://upstash.com/docs/redis/commands/pub-sub/unsubscribe + +Use `UNSUBSCRIBE` to cancel channel subscriptions of the current connection. + +With no arguments the connection unsubscribes from every channel it is subscribed to, otherwise only from the ones named. The server sends one confirmation per channel, each carrying the number of subscriptions still active, and the connection leaves subscriber mode once that count reaches zero. + +Pattern subscriptions are not affected; cancel those with [`PUNSUBSCRIBE`](/docs/redis/commands/pub-sub/punsubscribe). + +## Syntax + +```redis +UNSUBSCRIBE [ [ ...]] +``` + +## Arguments + +| Argument | Required | Repeatable | Description | +| --- | --- | --- | --- | +| `` | No | Yes | Channel name. | + +## Important points + +* This is a connection-oriented command and is available over native Redis TCP, not the stateless REST endpoint. +* Subscription commands require a dedicated TCP connection. In RESP3, subscription events use push replies. + +## Response + +The reply reports the result of the operation. Error replies have the same shape in RESP2 and RESP3 and are surfaced as exceptions by the SDKs below. + +| Protocol | Reply | +| --- | --- | +| RESP2 | Three-element subscription-state array per channel | +| RESP3 | Three-element subscription-state push reply per channel | + + + Client libraries often decode bulk strings, maps, sets, and numeric strings into language-native values. The table describes the Redis wire reply. + + +## Examples + +TCP examples use the TLS `REDIS_URL` from the Upstash console. REST examples use `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN`. + + + + + +```bash +UNSUBSCRIBE events +``` + + + + + +```ts +import Redis from "ioredis"; + +const subscriber = new Redis(process.env.REDIS_URL!); +await subscriber.subscribe("events"); +await subscriber.unsubscribe("events"); +``` + + + + + +```ts +import { createClient } from "redis"; + +const subscriber = await createClient({ url: process.env.REDIS_URL }).connect(); +await subscriber.subscribe("events", console.log); +await subscriber.unsubscribe("events"); +``` + + + + + +```python +import os +import redis + +client = redis.from_url(os.environ["REDIS_URL"]) +pubsub = client.pubsub() +pubsub.subscribe("events") +pubsub.unsubscribe("events") +``` + + + + + +```go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/redis/go-redis/v9" +) + +func main() { + ctx := context.Background() + opts, err := redis.ParseURL(os.Getenv("REDIS_URL")) + if err != nil { + panic(err) + } + client := redis.NewClient(opts) + pubsub := client.Subscribe(ctx, "events") + if err := pubsub.Unsubscribe(ctx, "events"); err != nil { + panic(err) + } +} +``` + + + + + +```java +import java.net.URI; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPubSub; + +try (Jedis jedis = new Jedis(new URI(System.getenv("REDIS_URL")))) { + jedis.subscribe(new JedisPubSub() { + @Override + public void onMessage(String channel, String message) { + unsubscribe(); + } + }, "events"); +} +``` + + + + + +```rust +fn main() -> redis::RedisResult<()> { + let url = std::env::var("REDIS_URL").expect("REDIS_URL is not set"); + let client = redis::Client::open(url)?; + let mut connection = client.get_connection()?; + let mut pubsub = connection.as_pubsub(); + pubsub.subscribe("events")?; + pubsub.unsubscribe("events")?; + #[allow(unreachable_code)] + Ok(()) +} +``` + + + + + +# EVAL +Source: https://upstash.com/docs/redis/commands/scripting/eval + +Use `EVAL` to run a Lua script on the server. + +`` says how many of the arguments that follow are key names. The script receives those in the `KEYS` table and every remaining argument in `ARGV`. Passing key names as keys rather than hardcoding them in the script body matters, because Redis uses that list for routing and access checks. Inside the script, `redis.call` runs Redis commands and its return value is converted to a Lua value. + +The script runs as a single atomic step, which makes it the standard way to do read, decide, and write logic, such as a rate limiter or a compare-and-set update, in one round trip and without a transaction. Keep scripts short, since a script that holds the database blocks everything else, and keep them deterministic by deriving values from `KEYS`, `ARGV`, or data read inside the script rather than from clock or random sources. + +Upstash isolates a script with a lock. By default that is the global lock, because the engine cannot know in advance which keys the script will touch, so no other command runs while the script does. Adding the `allow-key-locking` flag to the script's shebang line makes it lock only the keys passed in `KEYS` instead, so calls that work on disjoint keys run in parallel: + +```lua +#!lua flags=allow-key-locking + +redis.call('INCR', KEYS[1]) +return 1 +``` + +With the flag set, every key the script touches must appear in `KEYS`, and commands that need database-wide access, such as `FLUSHDB`, are rejected. See [Key-Based Locking](/docs/redis/features/key-locking) for the full rules. + + + Pass every key the script touches through `KEYS`, even when the script runs + under the global lock. Upstash keeps idle entries + [on disk](/docs/redis/features/durability): declared keys are loaded before the + script starts and the lock is released during that read, but a key that the + script builds while it runs is read from disk with the lock held, stalling + every command waiting on it. See + [Dynamic Keys and Latency](/docs/redis/features/key-locking#dynamic-keys-and-latency). + + +Sending a script also caches it under its SHA1 digest, so later calls can use [`EVALSHA`](/docs/redis/commands/scripting/evalsha) and avoid resending the body. Use [`EVAL_RO`](/docs/redis/commands/scripting/eval-ro) for scripts that only read. + +## Syntax + +```redis +EVAL