Getting Started
Connect to Redis Server
redis-cli is the standard command-line client. Default connects to 127.0.0.1:6379. Use -h for host, -p for port, -a for password (or set REDISCLI_AUTH env var to avoid leaking secrets in shell history). TLS needs --tls plus cert/key. URL scheme redis:// is supported in Redis 6+, rediss:// for TLS.
# connect to local server (default port 6379)
redis-cli
# connect to a remote host with custom port
redis-cli -h redis.example.com -p 6380
# connect with authentication
redis-cli -a "yourpassword"
redis-cli -h host -p 6379 -a "yourpassword"
# connect over TLS
redis-cli --tls --cert client.crt --key client.key -h host -p 6379
# connect using a URL (Redis 6+)
redis-cli redis://user:password@host:6379/0
redis-cli rediss://user:password@host:6379/0 # TLSConnection Options & Mode
redis-cli supports both interactive and one-shot modes. Passing a command as arguments runs it and exits. Pipe mode reads RESP/text commands from stdin — great for scripting and bulk loads. -n selects the logical database. --stat and --latency are built-in monitoring helpers. --raw outputs values without type prefixes, useful for piping.
# select a specific database index (0-15)
redis-cli -n 1 # use database 1
# run a single command and exit (non-interactive)
redis-cli GET mykey
redis-cli -h host PING
# pass command with arguments
redis-cli SET counter 100
redis-cli INCR counter
# read commands from stdin (pipe mode)
echo "SET k1 v1" | redis-cli
cat commands.txt | redis-cli
# repeat a command every second (watch mode)
redis-cli --stat
redis-cli --latency
# pretty-print JSON output (Redis 6+)
redis-cli --raw GET user:jsonPING & Connectivity Test
PING is the simplest health check — a working Redis returns PONG. --latency continuously measures round-trip time (useful for diagnosing network issues). --latency-dist shows a histogram. --latency-history logs rolling stats. Use these to baseline your connection quality before performance tuning.
# basic connectivity test
redis-cli ping
# PONG
# ping with a message (echoed back)
redis-cli PING "hello"
# "hello"
# test auth + connection in one shot
redis-cli -a password PING
# check round-trip latency (continuous)
redis-cli --latency
# output: min: 0, max: 1, avg: 0.27 (3421 samples)
# latency histogram
redis-cli --latency-dist
# latency history (rolling, every 15s by default)
redis-cli --latency-history -i 1Interactive Mode Tips
Interactive mode is a REPL for Redis commands. HELP <command> or HELP @<group> shows built-in docs (no internet needed). CONNECT switches servers in-session. CLEAR clears the screen. The CLI auto-detects multi-line input for quoted strings. Prefix ':' to run CLI-specific commands (like :raw) vs Redis commands.
# start interactive mode
redis-cli
# inside the CLI:
127.0.0.1:6379> HELP SET # command help
127.0.0.1:6379> HELP @string # help for a command group
127.0.0.1:6379> SCAN 0 # any Redis command
# clear the screen
127.0.0.1:6379> CLEAR
# connect to a different server without restarting
127.0.0.1:6379> CONNECT host 6380
# exit
127.0.0.1:6379> EXIT
127.0.0.1:6379> QUIT
# multi-line input: end with a backslash
127.0.0.1:6379> SET mykey "this is \
a multi-line value"
# toggle raw output mode
127.0.0.1:6379> :rawDatabase Selection & Basics
Redis databases are logical namespaces (0-15) sharing the same memory — not isolated schemas. Most apps use only db 0. FLUSHDB clears the current db; FLUSHALL clears everything (be careful!). Multiple databases are discouraged in favor of separate instances or key prefixes, since they share a single thread.
# Redis has 16 logical databases (0-15) by default
SELECT 0 # switch to database 0
SELECT 15 # switch to database 15
# move a key to another database
MOVE mykey 1
# flush the current database (DESTRUCTIVE)
FLUSHDB
# flush ALL databases (VERY DESTRUCTIVE)
FLUSHALL
# get the number of keys in the current db
DBSIZE
# swap two databases (Redis 4.0+)
SWAPDB 0 1Help & Command Discovery
COMMAND introspects the server's command table — useful for discovering capabilities and arity. COMMAND DOCS (7.0+) returns structured documentation. The CLI's HELP command shows offline docs grouped by category (@string, @hash, @server, etc.). Run 'redis-cli --help' for all CLI flags and options.
# list all commands (huge output)
COMMAND
# get details of a specific command
COMMAND INFO GET
COMMAND INFO SET HSET LPUSH
# structured documentation (Redis 7+)
COMMAND DOCS SET
COMMAND DOCS @string
# count available commands
COMMAND COUNT
# CLI help
redis-cli --help
redis-cli --version
# inside interactive mode
HELP
HELP @server
HELP @string
HELP @hash
HELP GETSETStrings
Basic SET & GET
SET/GET are the fundamental string operations. NX = set if not exists (used for locks); XX = set if exists. EX/PX/EXAT/PXAT set expiration atomically (no race between SET and EXPIRE). GETSET returns the previous value while setting a new one. Strings are binary-safe up to 512MB.
# set and get a key
SET mykey "Hello"
GET mykey # "Hello"
# set only if not exists (NX) or only if exists (XX)
SET mykey "new" NX # set only if key does NOT exist
SET mykey "new" XX # set only if key DOES exist
# set with expiration (seconds / milliseconds)
SET token "abc" EX 3600 # expires in 3600s
SET token "abc" PX 60000 # expires in 60000ms
# set with expiration at a Unix timestamp
SET token "abc" EXAT 1700000000
# get and set atomically (returns old value)
GETSET counter 0 # returns old value, sets new
# delete a key
DEL mykeyNumeric Counters (INCR/DECR)
INCR/DECR are atomic — safe for concurrent access without locks. This makes Redis ideal for counters, rate limiting (INCR + EXPIRE), and generating sequence IDs. INCRBYFLOAT supports decimals but uses double precision (watch for rounding). If the value isn't an integer, INCR returns an error.
# increment a numeric string atomically
SET counter 100
INCR counter # 101
INCRBY counter 10 # 111
# decrement
DECR counter # 110
DECRBY counter 5 # 105
# floating point increment
SET price "10.50"
INCRBYFLOAT price 0.25 # "10.75"
INCRBYFLOAT price -1.00 # "9.75"
# all increment ops are atomic and concurrency-safe
# use for: counters, rate limiting, sequence IDs, stats
# INCR on a non-integer value returns an error
SET mystr "hello"
INCR mystr # ERROR: value is not an integerAPPEND & String Operations
APPEND extends a string (creates it if missing). STRLEN reports length. GETRANGE/SETRANGE operate on substrings (binary-safe). GETDEL (6.2+) atomically returns and deletes — useful for one-time-read patterns. GETEX atomically returns the value and sets a TTL — handy for refreshing session expiration on read.
# append to a string value
SET msg "Hello"
APPEND msg " World" # "Hello World"
# get string length
STRLEN msg # 11
# get substring
GETRANGE msg 0 4 # "Hello"
GETRANGE msg 6 -1 # "World"
# overwrite a substring (grows if needed)
SETRANGE msg 6 "Redis" # "Hello Redis"
# get and delete atomically
GETDEL mykey # returns value AND deletes key
# get and set expiration atomically (6.2+)
GETEX mykey EX 3600 # returns value, sets TTL
# append only if key exists
APPEND existing_key "more"MSET & MGET (Batch Operations)
MSET/MGET batch operations into one round-trip — essential for performance (Redis is single-threaded, so per-command overhead matters). MSETNX is atomic: either all keys are set or none. For many small key-value pairs, consider grouping them into a hash (HSET) for better memory efficiency via listpack encoding.
# set multiple keys at once (atomic)
MSET k1 "v1" k2 "v2" k3 "v3"
# get multiple keys at once
MGET k1 k2 k3 # 1) "v1" 2) "v2" 3) "v3"
# set multiple only if ALL keys are new
MSETNX k1 "v1" k4 "v4" # 1 if all set, 0 if any existed
# MSET/MGET reduce round-trips — much faster than
# separate SET/GET calls in a loop
# get the length of a string value
STRLEN k1 # 2
# set multiple fields of different keys is not possible;
# for per-field updates use hashes (HSET)
# pipeline alternative in CLI:
printf '%s\n' "SET k1 v1" "SET k2 v2" "GET k1" | redis-cli --pipe-modeBitmaps (String-based)
Bitmaps store boolean flags for up to 4 billion users in ~512MB — extremely space-efficient. BITOP AND/OR/XOR/NOT combine bitmaps (e.g., users active on multiple days). BITCOUNT counts active users. BITFIELD packs multiple small counters into one string. Position = user ID. Use cases: daily active users, feature flags.
# bitmaps are strings operated on at the bit level
# great for boolean flags on a large user base
# set bit at position (0 or 1)
SETBIT user:1:active 7 1 # user 1 active
GETBIT user:1:active 7 # 1
# count set bits
BITCOUNT user:1:active # total bits set to 1
# bitwise operations between strings
SETBIT users:d1 5 1
SETBIT users:d2 5 1
BITOP AND active-both users:d1 users:d2
BITCOUNT active-both # users active on both days
BITOP OR active-either users:d1 users:d2
BITOP XOR diff users:d1 users:d2
# find the first set bit
BITPOS user:1:active 1 # position of first 1-bit
# bitfield: multiple counters in one string
BITFIELD mycnt SET u8 0 100
BITFIELD mycnt INCRBY u8 0 10String Expiration & TTL
TTL returns -2 for non-existent keys and -1 for keys without expiration. SET with EX is atomic (no race between SET and EXPIRE). KEEPTTL (6.0+) lets you update a value while preserving its TTL — useful for refreshing cached values without resetting the expiration window. Expiration is lazy (checked on access) plus periodic background sweeps.
# set a key with expiration in one atomic command
SET session "data" EX 3600 # 1 hour
SET cache "value" PX 60000 # 60 seconds (ms)
# set expiration on an existing key
EXPIRE mykey 60 # 60 seconds
PEXPIRE mykey 60000 # 60 seconds (ms)
EXPIREAT mykey 1700000000 # Unix timestamp
# view remaining time to live
TTL mykey # seconds (-1 = no expiry, -2 = no key)
PTTL mykey # milliseconds
# remove expiration (make key persistent)
PERSIST mykey
# TTL with KEEPTTL option (6.0+): set value, keep existing TTL
SET mykey "newval" KEEPTTLLists
Push & Pop Operations
Lists are double-ended: LPUSH+RPOP = queue (FIFO), LPUSH+LPOP = stack (LIFO). BLPOP/BRPOP block until an item is available — the foundation of Redis queues (no polling needed). Always set a timeout on BLPOP to handle disconnects. Lists are O(1) for head/tail operations but O(N) for middle access.
# lists are ordered sequences of strings (linked lists)
LPUSH mylist "a" "b" # list: [b, a]
RPUSH mylist "c" # list: [b, a, c]
# pop from head or tail
LPOP mylist # "b" (removes from head)
RPOP mylist # "c" (removes from tail)
# pop multiple (6.2+)
LPOP mylist 2 # pop 2 from head
# get length
LLEN mylist # 0
# blocking pop (waits if empty, up to timeout)
BLPOP queue:tasks 30 # blocks up to 30 seconds
BRPOP queue:tasks 0 # blocks forever
# push only if the list exists (don't create new key)
LPUSHX mylist "x" # 0 if key doesn't existLRANGE & Indexing
LRANGE 0 -1 returns the whole list. LINDEX is O(N) for middle elements — lists are optimized for end access. LSET modifies by index. LINSERT is O(N) (use sparingly on large lists). LPOS finds element positions without removing them. For frequent random access by index, a list is the wrong choice — consider a sorted set.
# get a range of elements (0-based, negative from end)
LRANGE mylist 0 -1 # all elements
LRANGE mylist 0 2 # first 3 elements
LRANGE mylist -3 -1 # last 3 elements
# get element by index (O(N) traversal)
LINDEX mylist 0 # first element
LINDEX mylist -1 # last element
# set an element by index
LSET mylist 1 "newval"
# get length
LLEN mylist
# insert before or after a pivot element
LINSERT mylist BEFORE "pivot" "new"
LINSERT mylist AFTER "pivot" "new"
# find the position of an element (6.0+)
LPOS mylist "value"
LPOS mylist "value" RANK 2 # find 2nd occurrenceBlocking Pops & Queues
BRPOPLPUSH/BLMOVE moves an item atomically from source to destination — the consumer can process it safely, and if it crashes, the item is still in the destination (reliable queue pattern). This beats BRPOP+processing because a crash after BRPOP loses the item. After processing, delete from the destination list.
# simple FIFO queue: LPUSH to add, RPOP to consume
LPUSH tasks "job1" "job2"
RPOP tasks # "job1" (FIFO order)
# reliable queue with BRPOP (blocking, waits for work)
BRPOP tasks 0 # blocks until a task is available
# move items between lists atomically
RPOPLPUSH source destination # move one item
# blocking move (reliable queue pattern)
BRPOPLPUSH source destination 30 # blocks up to 30s
# Redis 6.2+: BLMOVE replaces BRPOPLPUSH
BLMOVE source destination RIGHT LEFT 30
# capped queue (e.g., recent events)
LPUSH recent "event"
LTRIM recent 0 99 # keep latest 100LREM, LSET & LTRIM
LTRIM is a common pattern to cap list size (e.g., keep only the latest 100 events). LREM removes by value (count: positive=head, negative=tail, 0=all). LMPOP (7.0+) pops from multiple lists in one call, useful for prioritized queues. For frequent middle-of-list operations, a list is the wrong choice.
# trim to a range (removes everything outside)
LTRIM mylist 0 99 # keep only first 100 elements
LTRIM mylist -50 -1 # keep only last 50
# remove elements by value
LREM mylist 2 "value" # remove first 2 occurrences of "value"
LREM mylist -2 "value" # remove last 2 occurrences
LREM mylist 0 "value" # remove ALL occurrences
# pop and push in one atomic operation
RPOPLPUSH source dest
# pop from multiple lists (7.0+)
LMPOP 2 mylist1 mylist2 LEFT COUNT 3
# blocking pop from multiple lists (7.0+)
BLMPOP 30 2 mylist1 mylist2 LEFT COUNT 3
# remove a key only if it's a list (type-safe)
DEL mylist # works on any typeList Use Cases
Lists are best for sequences with end-access patterns: queues, stacks, feeds, buffers. LTRIM makes them ideal for capped logs/feeds. For rate limiting, a list of timestamps + LTRIM is a simple sliding window. For sorted/prioritized queues, use a sorted set instead. Lists don't support deduplication — use a set for that.
# 1. Task queue (FIFO)
LPUSH tasks "process_order:123"
BRPOP tasks 30
# 2. Recent activity feed (capped)
LPUSH user:1:feed "post:99" "post:98"
LTRIM user:1:feed 0 49 # latest 50
# 3. Stack (LIFO)
LPUSH stack "item"
LPOP stack
# 4. Circular buffer (limited size)
LPUSH buffer "new"
LTRIM buffer 0 999 # keep 1000 items
# 5. Rate limiter (sliding window)
LPUSH rate:user:1 1700000000
LTRIM rate:user:1 0 99
LLEN rate:user:1 # request count in window
# 6. Chat history (capped)
LPUSH chat:room:1 "alice: hello"
LTRIM chat:room:1 0 999 # keep last 1000 messagesSets
SADD, SMEMBERS & SISMEMBER
Sets store unique values — perfect for tags, categories, and deduplication. SISMEMBER is O(1) — far faster than checking a list. SMEMBERS can block on large sets; use SSCAN for iteration. SMISMEMBER (7.4+) batch-checks membership, reducing round-trips. Sets use intset (sorted array) when all members are integers — very memory-efficient.
# sets: unordered collection of unique strings
SADD tags "redis" "db" "cache"
SADD tags "redis" # ignored (already exists)
# check membership (O(1))
SISMEMBER tags "redis" # 1 if member, 0 if not
# get all members (avoid on large sets)
SMEMBERS tags # 1) "redis" 2) "db" 3) "cache"
# get the number of members
SCARD tags # 3
# remove a member
SREM tags "cache" # 1
# check multiple memberships at once (7.4+)
SMISMEMBER tags "redis" "db" "missing"
# 1) 1 2) 1 3) 0Set Operations (Union/Inter/Diff)
Set operations are Redis's superpower — union, intersection, and difference in O(N) without client-side processing. Use cases: mutual friends (SINTER), unique visitors (SUNION), tag-based filtering (SINTER of tag sets). SINTERCARD (7.0+) returns just the count, faster when you don't need the members. Store results to avoid recomputation.
# set union, intersection, difference
SADD set1 "a" "b" "c"
SADD set2 "b" "c" "d"
# union (all unique members from all sets)
SUNION set1 set2 # a, b, c, d
# intersection (members in ALL sets)
SINTER set1 set2 # b, c
# difference (members in set1 but NOT in set2)
SDIFF set1 set2 # a
# store the result in a new set
SUNIONSTORE result set1 set2
SINTERSTORE result set1 set2
SDIFFSTORE result set1 set2
# count intersection without returning members (7.0+)
SINTERCARD 2 set1 set2 LIMIT 0
# operations on multiple sets at once
SUNION s1 s2 s3 s4SREM, SMOVE & SPOP
SMOVE is atomic — useful for state transitions (e.g., move a user from 'pending' to 'active' set). SPOP removes random members (useful for lottery/sharding). SRANDMEMBER doesn't remove. BSPOP (7.0+) blocks like BLPOP but for sets — useful for event-driven patterns where order doesn't matter. SREM returns the count actually removed.
# remove one or more members
SADD myset "a" "b" "c" "d"
SREM myset "a" "b" # 2 (number removed)
# move a member from one set to another atomically
SMOVE source dest "member"
# pop a random member (removes it)
SPOP myset # removes and returns one
SPOP myset 3 # removes and returns 3 (6.2+)
# get a random member (does NOT remove)
SRANDMEMBER myset # one random member
SRANDMEMBER myset 3 # 3 random (may repeat)
SRANDMEMBER myset -3 # 3 unique random
# blocking set pop (7.0+) - waits until a member exists
BSPOP myset 30 # blocks up to 30 seconds
# delete the entire set
DEL mysetSSCAN Iteration
SSCAN is the safe way to iterate large sets — SMEMBERS blocks the server for huge sets. SSCAN is cursor-based: call repeatedly until the cursor returns to 0. COUNT is a hint (it may return more or fewer). SSCAN offers weak guarantees: it may return duplicates or miss members added during iteration, but it never blocks. Always handle the cursor loop in your code.
# SSCAN: cursor-based iteration for large sets
SSCAN myset 0 MATCH "pre*" COUNT 100
# returns: [nextCursor, [member1, member2, ...]]
# continue until cursor returns to 0
SSCAN myset <nextCursor> MATCH "pre*" COUNT 100
# iterate all members safely
cursor=0
while true:
cursor, members = SSCAN myset cursor COUNT 100
process(members)
if cursor == 0: break
# scan with type filtering (7.0+ for SCAN, sets always same type)
# COUNT is a hint, not exact (may return more or fewer)
# MATCH pattern supports glob: *, ?, [abc]
SSCAN myset 0 MATCH "user:*" COUNT 1000
# for small sets, SMEMBERS is fine
# for large sets (>10k), always use SSCANSet Use Cases
Sets are the go-to for uniqueness and relationships. The SINTER pattern for mutual followers/friends is a classic. For 'visitors per day' with huge cardinality, consider HyperLogLog (approximate but fixed 12KB). For ordered unique data (leaderboards), use a sorted set. Sets are unordered — if order matters, use a list or sorted set.