---
title: "Redis"
description: "Comprehensive Redis reference guide covering commands, data types, keys, strings, lists, sets, hashes, sorted sets, transactions, pub/sub, and caching strategies."
author: "Mohammad Abu Mattar"
canonical: https://mkabumattar.com/cheatsheets/redis
---

# Redis

Comprehensive Redis reference guide covering commands, data types, keys, strings, lists, sets, hashes, sorted sets, transactions, pub/sub, and caching strategies.

## Getting Started

### Redis CLI Basics

Connect and interact with Redis using redis-cli command-line tool

**Keywords:** redis-cli, connection, authentication, select database

#### Connect to Local Redis Default

```bash
redis-cli
```

_exec_
```text
127.0.0.1:6379>
```

Opens interactive Redis CLI session on localhost port 6379

- Default Redis server runs on port 6379
- Requires Redis server to be running
- Ctrl+C to exit the CLI

#### Connect to Remote Redis Server

```bash
redis-cli -h redis.example.com -p 6380 -a yourpassword
```

_exec_
```text
redis.example.com:6380>
```

Connect to Redis on host redis.example.com with port 6380 and password authentication

- -h specifies hostname or IP address
- -p specifies custom port
- -a provides password authentication

#### Execute Command from Command Line

```bash
redis-cli PING
```

_exec_
```text
PONG
```

Execute a single command without entering interactive mode

- Useful for scripts and automation
- Returns result to stdout

#### Select Database Index

```bash
redis-cli
127.0.0.1:6379> SELECT 1
```

_exec_
```text
OK
127.0.0.1:6379[1]>
```

Switch to database 1 (Redis has 16 databases by default, indexed 0-15)

- Each database has separate keyspace
- Default is database 0
- Useful for testing without affecting production data

**Best practices:**

- Always authenticate when connecting to production servers
- Use connection pooling in applications
- Specify explicit port and host for clarity
- Use SELECT carefully in scripts to avoid database number mistakes

**Common errors:**

- **Connection refused**: Ensure Redis server is running on specified host/port'
- **Authentication required**: Wrong or missing password with -a flag
- **Database index out of range**: Valid indices are 0-15 for default config

### INFO Command and Server Stats

Retrieve comprehensive Redis server information and statistics

**Keywords:** INFO, server statistics, memory usage, connected clients

#### Get All Server Information

```bash
redis-cli INFO
```

_exec_
```text
# Server
redis_version:7.0.0
redis_mode:standalone
os:Linux 5.15.0 x86_64
arch_bits:64
uptime_in_seconds:3456
uptime_in_days:0
# Clients
connected_clients:42
blocked_clients:0
# Memory
used_memory:1048576
used_memory_human:1.00M
maxmemory:0
# Stats
total_connections_received:156
total_commands_processed:8923
```

Displays all available server information across all sections

- Output is formatted in sections starting with
- Large output on busy servers
- Shows uptime, client count, memory usage, commands processed

#### Get Specific Section Only

```bash
redis-cli INFO memory
```

_exec_
```text
# Memory
used_memory:2097152
used_memory_human:2.00M
used_memory_rss:4194304
maxmemory:1073741824
maxmemory_human:1.00G
maxmemory_policy:noeviction
```

Retrieve memory statistics only (more targeted than INFO all)

- Available sections: server, clients, memory, persistence, stats, replication, cpu, cluster, modules
- Useful for monitoring specific metrics

#### Check Connected Clients and Commands

```bash
redis-cli INFO stats
```

_exec_
```text
# Stats
total_connections_received:523
total_commands_processed:12543
instantaneous_ops_per_sec:45
evicted_keys:3
```

Monitor requests per second and total throughput metrics

- ops_per_sec shows current command rate
- evicted_keys indicates memory pressure
- Useful for performance monitoring

**Best practices:**

- Monitor memory usage regularly to avoid eviction
- Check maxmemory policy matches your use case
- Use specific sections when integrating with monitoring tools
- Track connected_clients to detect connection leaks

**Common errors:**

- **Wrong number of arguments**: Use INFO section_name for specific info
- **Parsing INFO output**: Numbers are strings in bash, cast to int if needed

### Configuration Commands

View and modify Redis server configuration at runtime

**Keywords:** CONFIG GET, CONFIG SET, runtime configuration, persistence settings

#### Get Configuration Value

```bash
redis-cli CONFIG GET maxmemory
```

_exec_
```text
1) "maxmemory"
2) "1073741824"
```

Retrieve current value of maxmemory configuration parameter

- Returns array with parameter name and value
- Value is in bytes

#### Get Multiple Configuration Parameters

```bash
redis-cli CONFIG GET "max*"
```

_exec_
```text
1) "maxmemory"
2) "1073741824"
3) "maxmemory-policy"
4) "noeviction"
```

Use wildcard patterns to retrieve related parameters

- Supports glob patterns like max*, *memory*
- Useful for exploring configuration space

#### Set Configuration Value

```bash
redis-cli CONFIG SET maxmemory 2147483648
```

_exec_
```text
OK
```

Change maxmemory to 2GB at runtime without restart

- Not all parameters can be changed at runtime
- Changes persist only during session unless saved to config file

#### Rewrite Configuration to File

```bash
redis-cli CONFIG REWRITE
```

_exec_
```text
OK
```

Save all runtime configuration changes to the config file

- Preserves comments and structure of original file
- Makes runtime changes permanent

**Best practices:**

- Test configuration changes on non-production first
- Always rewrite config after runtime changes you want to keep
- Set maxmemory-policy based on use case (volatile-lru for caching)
- Monitor memory with CONFIG GET to prevent OOM errors

**Common errors:**

- **ERR Unknown CONFIG subcommand**: Check spelling of parameter name
- **Config value out of range**: Ensure new value is in valid range

### Connection Pooling Concepts

Understanding and managing Redis client connections efficiently

**Keywords:** connection pooling, persistent connections, client list, HELLO protocol

#### List All Connected Clients

```bash
redis-cli CLIENT LIST
```

_exec_
```text
id=1 addr=127.0.0.1:45678 fd=8 name= age=15 idle=0 flags=N db=0 sub=0 psub=0 multi=-1
id=2 addr=127.0.0.1:45679 fd=9 name= age=2 idle=1 flags=N db=0 sub=0 psub=0 multi=-1
```

Display list of all clients connected to Redis server

- Each line represents one client connection
- idle shows seconds since last command
- flags: N=normal, d=dirty, R=readonly, etc.

#### Get Client Connection Count

```bash
redis-cli INFO clients | grep connected_clients
```

_exec_
```text
connected_clients:8
```

Quick way to check current number of connected clients

- Monitor this metric to detect connection leaks
- Compare with maxclients setting

#### Kill Idle Client Connection

```bash
redis-cli CLIENT KILL 127.0.0.1:45678
```

_exec_
```text
OK
```

Terminate specific client connection by address

- Useful for removing stuck or idle connections
- Client will reconnect if pool is configured

#### Set Client Name for Tracking

```bash
redis-cli CLIENT SETNAME "app-worker-1"
```

_exec_
```text
OK
```

Assign name to current connection for monitoring purposes

- Visible in CLIENT LIST output
- Helpful for debugging multiple connections

**Best practices:**

- Use connection pooling in applications (min 5, max 20 connections)
- Monitor connected_clients in production
- Set reasonable PING intervals in pools to detect dead connections
- Use CLIENT SETNAME to identify connection sources in logs

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

## Keys Management

### Key Deletion and Existence

Check existence and delete keys from Redis database

**Keywords:** DEL, EXISTS, UNLINK, key deletion

#### Delete Single Key

```bash
redis-cli SET mykey "Hello"
redis-cli DEL mykey
```

_exec_
```text
OK
(integer) 1
```

Create and delete a key, DEL returns number of keys deleted

- Returns the count of keys actually deleted
- Returns 0 if key doesn't exist
- Synchronous operation

#### Delete Multiple Keys

```bash
redis-cli DEL user:1 user:2 user:3 session:abc
```

_exec_
```text
(integer) 4
```

Delete multiple keys in one command, returns total deleted count

- More efficient than multiple DEL commands
- Atomic operation - deletes all or none

#### Check If Key Exists

```bash
redis-cli EXISTS mykey
```

_exec_
```text
(integer) 1
```

Returns 1 if key exists, 0 if it doesn't

- Fast O(1) operation
- Can check multiple keys, returns sum of existing keys

#### Check Multiple Keys for Existence

```bash
redis-cli EXISTS user:1 user:2 user:3 nonexistent
```

_exec_
```text
(integer) 3
```

Returns count of how many keys exist among the given ones

- Useful for batch existence checks

#### Asynchronous Key Deletion

```bash
redis-cli UNLINK large_list large_hash large_set
```

_exec_
```text
(integer) 3
```

Non-blocking deletion, especially useful for large keys

- Faster than DEL for large data structures
- Deletes in background thread
- Same return value as DEL

**Best practices:**

- Use UNLINK for large keys to avoid blocking
- Check EXISTS before expensive operations
- Batch deletes with multiple keys for efficiency
- Be cautious with DEL on patterns (use SCAN+DEL instead)

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Key Expiration and TTL

Set and manage key expiration times

**Keywords:** EXPIRE, TTL, EXPIREAT, PEXPIRE, persistence settings

#### Set Key Expiration in Seconds

```bash
redis-cli SET session:token "abc123xyz"
redis-cli EXPIRE session:token 3600
```

_exec_
```text
OK
(integer) 1
```

Set key to expire in 3600 seconds (1 hour)

- Returns 1 if timeout set, 0 if key doesn't exist
- Session keys typically use EXPIRE

#### Check Remaining Time To Live

```bash
redis-cli TTL session:token
```

_exec_
```text
(integer) 3598
```

Returns seconds remaining until key expires

- Returns -1 if key exists but has no expiration
- Returns -2 if key doesn't exist
- Use PTTL for millisecond precision

#### Set Millisecond Expiration

```bash
redis-cli PEXPIRE rate-limit:user123 5000
```

_exec_
```text
(integer) 1
```

Set key to expire in exactly 5000 milliseconds (5 seconds)

- Useful for rate limiting and short-lived data
- PTTL returns milliseconds remaining

#### Set Expiration at Unix Timestamp

```bash
redis-cli EXPIREAT cache:data 1704067200
```

_exec_
```text
(integer) 1
```

Set key to expire at specific Unix timestamp (Jan 1, 2024)

- timestamp is in seconds since Unix epoch
- Useful when you know exact expiration time

#### Remove Key Expiration

```bash
redis-cli PERSIST session:token
```

_exec_
```text
(integer) 1
```

Remove expiration from key, making it permanent

- Returns 1 if timeout removed, 0 if already permanent or doesn't exist

#### Set Value with Expiration in One Command

```bash
redis-cli SET otp:email@example.com "654321" EX 300
```

_exec_
```text
OK
```

Set key with value and 300-second expiration in single command

- EX = expire in seconds, PX = expire in milliseconds
- More efficient than SET followed by EXPIRE
- NX/XX options work with EX/PX

**Best practices:**

- Always set expiration on temporary data (sessions, OTPs, cache)
- [object Object]
- Monitor expired keys with CONFIG GET "lazyfree-lazy-eviction"
- Set slightly longer TTL than needed to avoid premature expiration

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined
- **undefined**: undefined

### Key Scanning and Enumeration

Iterate through keys without blocking Redis server

**Keywords:** SCAN, pattern matching, cursor iteration, non-blocking enumeration

#### Scan All Keys with Cursor

```bash
redis-cli SCAN 0
```

_exec_
```text
1) "2048"
2) 1) "user:profile:123"
   2) "session:token:abc"
   3) "cache:homepage"
```

Start scanning from cursor 0, returns next cursor and matching keys

- Returns [next_cursor, [keys]]
- Continue with cursor 2048 to get more keys
- O(1) per iteration, doesn't block server

#### Scan with Pattern Match

```bash
redis-cli SCAN 0 MATCH "user:*"
```

_exec_
```text
1) "1024"
2) 1) "user:profile:1"
   2) "user:profile:2"
   3) "user:settings:100"
```

Scan only keys matching "user:*" pattern

- Pattern matching happens on server side
- Still uses cursor iteration, not all-at-once retrieval

#### Scan with Count Hint

```bash
redis-cli SCAN 0 COUNT 100
```

_exec_
```text
1) "512"
2) 1) "cache:data:1"
   2) "cache:data:2"
   3) "cache:data:3"
```

Return approximately 100 keys per iteration

- COUNT is hint, not strict count
- Larger COUNT may return many keys
- Useful for batch operations

#### Complete Scan Iteration in Bash

```bash
cursor=0
while true; do
  result=$(redis-cli SCAN $cursor MATCH "session:*" COUNT 50)
  cursor=$(echo "$result" | head -1)
  echo "$result" | tail -1
  [[ $cursor -eq 0 ]] && break
done
```

_exec_
```text
session:user1
session:user2
session:user3
[... more sessions ...]
```

Loop through all keys matching pattern until cursor returns to 0

- Proper way to enumerate all keys when using SCAN
- Safe for production use

#### Scan Hash Fields

```bash
redis-cli HSCAN user:1:profile 0
```

_exec_
```text
1) "0"
2) 1) "name"
   2) "John Doe"
   3) "email"
   4) "john@example.com"
```

Scan fields of hash without loading all fields at once

- Works similarly to SCAN with cursor-based iteration
- Also available as SSCAN for sets, ZSCAN for sorted sets

**Best practices:**

- Always use SCAN for large datasets, never use KEYS pattern
- Handle cursor=0 as end condition in loops
- Use MATCH pattern to filter results server-side
- Implement timeout to prevent infinite loops

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined
- **undefined**: undefined

### Key Type Checking and Operations

Determine and manipulate key data types

**Keywords:** TYPE, DUMP, RESTORE, COPY, MIGRATE

#### Check Key Data Type

```bash
redis-cli SET mystring "hello"
redis-cli LPUSH mylist "item1"
redis-cli TYPE mystring
redis-cli TYPE mylist
```

_exec_
```text
OK
(integer) 1
string
list
```

Returns the data type of specified key

- Returns: string, list, set, zset, hash, stream
- Returns "none" for non-existent keys

#### Dump and Restore Key

```bash
redis-cli SET backup-key "important data"
redis-cli DUMP backup-key
```

_exec_
```text
OK
"\x00\x10important data\x09\x00\x8f\xf6\x8f\xf6\x00\x00\x00\x00"
```

Serialize key content for backup or transfer

- Returns serialized value in Redis protocol format
- Can be restored with RESTORE command in different instance

#### Copy Key to New Name

```bash
redis-cli SET original-key "data"
redis-cli COPY original-key backup-key
```

_exec_
```text
OK
(integer) 1
```

Create copy of key with new name

- Returns 1 on success, 0 if destination already exists
- Use REPLACE option to overwrite destination

#### Get Key Memory Usage

```bash
redis-cli MEMORY USAGE mykey
```

_exec_
```text
(integer) 56
```

Returns memory consumption of key in bytes

- Includes Redis internal overhead
- Useful for determining memory efficiency

**Best practices:**

- Check TYPE before operations that expect specific data type
- Use DUMP/RESTORE for backup or cross-instance migration
- Monitor MEMORY USAGE for large keys
- Document your key naming conventions for type inference

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Key Renaming and Moving

Rename keys or move them to different databases

**Keywords:** RENAME, RENAMENX, MOVE, atomic operations

#### Rename Key

```bash
redis-cli SET old-name "content"
redis-cli RENAME old-name new-name
redis-cli GET new-name
```

_exec_
```text
OK
OK
"content"
```

Rename key atomically, old key is replaced with new name

- Returns error if source key doesn't exist
- Overwrites destination key if it exists

#### Rename Only If New Name Doesn't Exist

```bash
redis-cli RENAMENX temp-data permanent-data
```

_exec_
```text
(integer) 1
```

Rename only if destination key doesn't already exist

- Returns 1 if renamed, 0 if destination exists
- Useful for conditional renames

#### Move Key to Different Database

```bash
redis-cli SELECT 0
127.0.0.1:6379[0]> SET migration-key "data"
127.0.0.1:6379[0]> MOVE migration-key 1
127.0.0.1:6379[0]> SELECT 1
127.0.0.1:6379[1]> GET migration-key
```

_exec_
```text
OK
(integer) 1
"data"
```

Atomically move key from one database to another

- Returns 1 on success, 0 if key doesn't exist or destination exists
- Useful for segregating data by type

**Best practices:**

- Use RENAMENX for safe renames to prevent data loss
- Separate concerns by database when appropriate
- Plan key naming conventions to minimize renaming
- Consider key migration strategy for growing applications

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

## String Operations

### String Get and Set Operations

Store and retrieve string values with various options

**Keywords:** SET, GET, GETSET, MGET, MSET

#### Set and Get Simple String

```bash
redis-cli SET user:1:name "Alice"
redis-cli GET user:1:name
```

_exec_
```text
OK
"Alice"
```

Basic string storage and retrieval

- Strings can be up to 512MB
- GET returns nil if key doesn't exist

#### Get Multiple Keys At Once

```bash
redis-cli MSET user:1:name "Alice" user:2:name "Bob" user:3:name "Charlie"
redis-cli MGET user:1:name user:2:name user:3:name
```

_exec_
```text
OK
1) "Alice"
2) "Bob"
3) "Charlie"
```

Set multiple key-value pairs and retrieve them together

- MGET is more efficient than multiple GET commands
- Returns nil for non-existent keys in array

#### Get and Set New Value Atomically

```bash
redis-cli SET config:api-key "old-key-123"
redis-cli GETSET config:api-key "new-key-456"
```

_exec_
```text
OK
"old-key-123"
```

Retrieve old value while setting new one in one operation

- Returns BEFORE value, not after
- Useful for rotating tokens or credentials

#### Set with Expiration Options

```bash
redis-cli SET cache:homepage "<html>...</html>" EX 3600
redis-cli SET cache:sidebar "{\"items\": [...]}" PX 5000
```

_exec_
```text
OK
OK
```

Set strings with automatic expiration in seconds (EX) or milliseconds (PX)

- EX = expire in seconds, PX = expire in milliseconds
- Common pattern for cache data

#### Set Only If Key Doesn't Exist

```bash
redis-cli SET user:registration:lock "processing" NX
redis-cli SET user:registration:lock "done" NX
```

_exec_
```text
OK
(nil)
```

Use NX to set only if key doesn't exist

- Returns OK on success, nil if key already exists
- Useful for distributed locks and ensuring single execution

#### Set Only If Key Already Exists

```bash
redis-cli SET counter "0"
redis-cli SET counter "1" XX
redis-cli SET nonexistent "value" XX
```

_exec_
```text
OK
OK
(nil)
```

Use XX to set only if key already exists

- XX = only update existing keys
- Prevents creating new keys accidentally

**Best practices:**

- Use EX/PX directly in SET instead of separate EXPIRE command
- Use MSET/MGET for multiple keys to reduce round trips
- Use NX for locks and single-execution patterns
- Validate JSON content before storing as strings

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### String Manipulation Commands

Modify and manipulate string values

**Keywords:** APPEND, STRLEN, GETRANGE, SETRANGE, SUBSTR

#### Append to String

```bash
redis-cli SET message "Hello"
redis-cli APPEND message " World"
redis-cli GET message
```

_exec_
```text
OK
(integer) 11
"Hello World"
```

Add text to end of existing string, returns new length

- If key doesn't exist, APPEND creates it
- Returns the length of string after appending

#### Get String Length

```bash
redis-cli SET filename "document.pdf"
redis-cli STRLEN filename
```

_exec_
```text
OK
(integer) 12
```

Get length of string value in characters

- Returns 0 for non-existent keys
- O(1) operation

#### Get Substring from String

```bash
redis-cli SET email "user@example.com"
redis-cli GETRANGE email 0 3
redis-cli GETRANGE email 5 -1
```

_exec_
```text
OK
"user"
"example.com"
```

Extract substring using start and end positions

- Supports negative indices from end of string
- -1 means last character

#### Set Substring in String

```bash
redis-cli SET data "Hello World"
redis-cli SETRANGE data 6 "Redis"
redis-cli GET data
```

_exec_
```text
OK
(integer) 11
"Hello Redis"
```

Replace portion of string starting at offset

- Extends with null bytes if necessary
- Returns length of resulting string

**Best practices:**

- Use APPEND for building logs or messages incrementally
- Validate string length before SETRANGE to avoid unexpected results
- Use GETRANGE for extracting parts (email domain, etc.)
- Consider JSON if frequent string manipulation is needed

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### String Numeric Operations

Increment, decrement, and perform math on numeric strings

**Keywords:** INCR, DECR, INCRBY, DECRBY, INCRBYFLOAT, GETEX

#### Increment Integer Value

```bash
redis-cli SET counter "10"
redis-cli INCR counter
redis-cli GET counter
```

_exec_
```text
OK
(integer) 11
"11"
```

Increment numeric string by 1, returns new value

- String must be valid integer format
- Returns error if not numeric
- Atomic operation, safe for concurrent access

#### Increment by Specific Amount

```bash
redis-cli SET page-views:today "1000"
redis-cli INCRBY page-views:today 50
```

_exec_
```text
OK
(integer) 1050
```

Add specific value to numeric string

- Works with negative values for subtraction
- Useful for counters and metrics

#### Decrement Value

```bash
redis-cli SET inventory:item-5 "100"
redis-cli DECR inventory:item-5
redis-cli DECRBY inventory:item-5 10
```

_exec_
```text
OK
(integer) 99
(integer) 89
```

Decrement value by 1 or specific amount

- Useful for stock management
- DECRBY with negative number acts as increment

#### Increment Float Value

```bash
redis-cli SET temperature "20.5"
redis-cli INCRBYFLOAT temperature 0.3
redis-cli GET temperature
```

_exec_
```text
OK
"20.8"
"20.8"
```

Add decimal increment to numeric string

- Accuracy of 17 digits
- Returns new value as string

#### Get and Update Expiration

```bash
redis-cli SET rate-limit:ip "5" EX 60
redis-cli GETEX rate-limit:ip EX 120
```

_exec_
```text
OK
"5"
```

Get value and update its expiration in one command

- More efficient than GET + EXPIRE
- Can also use EXAT, PERSIST options

**Best practices:**

- Use INCR for atomic counters without race conditions
- Use INCRBY for batch increments (multiple page views)
- INCRBYFLOAT for metrics like temperature, prices
- Always verify numeric format before INCR/DECR

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### String Bit Operations

Bitwise operations on string values

**Keywords:** SETBIT, GETBIT, BITCOUNT, BITOP, BITPOS

#### Set Individual Bit

```bash
redis-cli SETBIT flags 7 1
redis-cli GETBIT flags 7
redis-cli GET flags
```

_exec_
```text
(integer) 0
(integer) 1
"\x01"
```

Set specific bit position and retrieve its value

- Bit position is 0-indexed
- Returns previous bit value
- Useful for compact flag storage

#### Count Set Bits

```bash
redis-cli SET bitmap "foobar"
redis-cli BITCOUNT bitmap
```

_exec_
```text
OK
(integer) 26
```

Count number of 1 bits in string

- Can specify byte range to count
- Useful for HyperLogLog-like operations

#### Bitwise Operations Between Values

```bash
redis-cli SET key1 "foobar"
redis-cli SET key2 "abcdef"
redis-cli BITOP AND dest key1 key2
redis-cli GET dest
```

_exec_
```text
OK
OK
(integer) 6
"`bc`ab"
```

Perform AND operation between two string values

- Supports AND, OR, XOR, NOT operations
- Returns length of result

#### Find First Set Bit

```bash
redis-cli SETBIT bits 10 1
redis-cli BITPOS bits 1
```

_exec_
```text
(integer) 0
(integer) 10
```

Find position of first bit set to 1

- Can search for 0 bits as well
- Returns -1 if no such bit exists

**Best practices:**

- Use bit operations for compact flag/status storage
- Combine with BITCOUNT for efficient counting
- Use BITOP for set operations on binary data
- Document bit positions in comments for clarity

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

## List Operations

### List Push and Pop Operations

Add and remove elements from list begins and ends

**Keywords:** LPUSH, RPUSH, LPOP, RPOP, LLEN, LINDEX

#### Push Elements to List

```bash
redis-cli LPUSH notifications "message1"
redis-cli LPUSH notifications "message2" "message3"
redis-cli LLEN notifications
```

_exec_
```text
(integer) 1
(integer) 3
(integer) 3
```

Add elements to left (beginning) of list, returns list length

- LPUSH adds to beginning, RPUSH adds to end
- Returns length after push operation
- Can push multiple items at once

#### Pop Elements from List

```bash
redis-cli LPOP notifications
redis-cli RPOP notifications
redis-cli LLEN notifications
```

_exec_
```text
"message3"
"message1"
(integer) 1
```

Remove and return element from left or right side

- LPOP removes from beginning (newest first LIFO)
- RPOP removes from end
- Returns nil if list is empty

#### Pop Multiple Elements

```bash
redis-cli RPUSH queue "task1" "task2" "task3" "task4"
redis-cli LPOP queue 2
```

_exec_
```text
(integer) 4
1) "task1"
2) "task2"
```

Remove multiple elements from list in single command

- COUNT parameter specifies how many to pop
- Reduces round trips for batch processing

#### Get Element at Index

```bash
redis-cli LINDEX notifications 0
redis-cli LINDEX notifications -1
```

_exec_
```text
"message2"
"message1"
```

Access element at specific position without removing it

- 0 is first element, -1 is last element
- Returns nil if index out of range
- O(n) operation, slower for large lists

#### Get List Length

```bash
redis-cli LLEN notifications
```

_exec_
```text
(integer) 2
```

Return number of elements in list

- Returns 0 for empty or non-existent keys
- O(1) operation

**Best practices:**

- Use lists for queues and stacks (FIFO/LIFO patterns)
- Batch pop operations to reduce network round trips
- Avoid accessing middle elements frequently (use sets instead)
- Monitor list length to detect unexpectedly large lists

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### List Range Operations

Get, set, and trim ranges of list elements

**Keywords:** LRANGE, LSET, LTRIM, LINSERT, LMOVE

#### Get Range of Elements

```bash
redis-cli RPUSH mylist "one" "two" "three" "four" "five"
redis-cli LRANGE mylist 0 2
redis-cli LRANGE mylist -2 -1
```

_exec_
```text
(integer) 5
1) "one"
2) "two"
3) "three"
1) "four"
2) "five"
```

Get elements between start and end indices (inclusive)

- Supports negative indices from end
- 0 to -1 returns all elements
- Returns empty array if range is invalid

#### Trim List to Range

```bash
redis-cli LTRIM mylist 0 2
redis-cli LRANGE mylist 0 -1
```

_exec_
```text
OK
1) "one"
2) "two"
3) "three"
```

Keep only elements in specified range, delete others

- Efficient way to limit list size
- Commonly used to keep only recent items

#### Set Element at Index

```bash
redis-cli LSET mylist 1 "TWO"
redis-cli LINDEX mylist 1
```

_exec_
```text
OK
"TWO"
```

Update element at specific position

- Returns error if index out of range
- O(n) operation

#### Insert Element Before or After Position

```bash
redis-cli LINSERT mylist BEFORE "TWO" "1.5"
redis-cli LRANGE mylist 0 -1
```

_exec_
```text
(integer) 4
1) "one"
2) "1.5"
3) "TWO"
4) "three"
```

Insert element before or after first occurrence of pivot value

- Returns -1 if pivot not found
- O(n) operation, slow for large lists

#### Move Element Between Lists

```bash
redis-cli RPUSH source "a" "b" "c"
redis-cli LMOVE source dest LEFT RIGHT
redis-cli LRANGE source 0 -1
redis-cli LRANGE dest 0 -1
```

_exec_
```text
(integer) 3
"a"
1) "b"
2) "c"
1) "a"
```

Atomically move element from source to destination list

- LEFT=pop from left, RIGHT=pop from right
- Destination receives from left or right
- Useful for rotating between lists

**Best practices:**

- Use LRANGE with 0 -1 to get all elements (up to reasonable size)
- LTRIM to keep only recent items (e.g., last 1000 messages)
- Don't use LINSERT on large lists (O(n) operation)
- Use LMOVE for atomic queue rotation

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### List Blocking Operations

Block and wait for list operations with timeout

**Keywords:** BLPOP, BRPOP, BRPOPLPUSH, BLMOVE, timeout

#### Blocking Pop Left

```bash
redis-cli BLPOP task-queue 0
# On another client:
# LPUSH task-queue "process-image.jpg"
```

_exec_
```text
# Waits until element available or timeout
1) "task-queue"
2) "process-image.jpg"
```

Block until element available in list or timeout reached

- Timeout 0 = wait forever
- Returns [key, value] when element available
- Multiple clients can block on same key

#### Blocking Pop with Timeout

```bash
redis-cli BLPOP empty-queue 5
```

_exec_
```text
# Waits 5 seconds then returns nil
(nil)
```

Return nil if nothing available after 5 seconds

- Timeout in seconds
- Useful for poll-based checking

#### Blocking Pop from Multiple Queues

```bash
redis-cli BLPOP queue1 queue2 queue3 0
```

_exec_
```text
1) "queue2"
2) "item-from-queue2"
```

Wait for element from any of multiple lists

- Returns as soon as element available in any list
- Last parameter is timeout
- Useful for priority queue patterns

#### Block and Move Between Lists

```bash
redis-cli BLMOVE source dest LEFT RIGHT 5
```

_exec_
```text
"moved-element"
```

Atomically pop from one list and push to another with blocking

- Returns popped element or nil on timeout
- Atomic operation, no race conditions

#### Blocking Pop and Push Pattern

```bash
redis-cli BRPOPLPUSH pending-tasks processing-tasks 10
```

_exec_
```text
"task-123"
```

Pop from pending, push to processing atomically

- Useful for task processing with automatic movement
- Element stays in processing list until explicitly removed

**Best practices:**

- Use BLPOP for worker processes waiting on task queues
- Set appropriate timeout (0 for infinite, or business timeout)
- Use BRPOPLPUSH for task states (pending→processing→done)
- Handle nil return when timeout occurs

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

## Set Operations

### Set Add and Remove Operations

Manage set membership and size

**Keywords:** SADD, SREM, SCARD, SMEMBERS, SISMEMBER

#### Add Elements to Set

```bash
redis-cli SADD tags "python" "redis" "database"
redis-cli SADD tags "python"
redis-cli SCARD tags
```

_exec_
```text
(integer) 3
(integer) 0
(integer) 3
```

Add members to set, duplicates are ignored

- Returns count of newly added members (not duplicates)
- Second SADD returns 0 because "python" already exists

#### Check Set Membership

```bash
redis-cli SISMEMBER tags "python"
redis-cli SISMEMBER tags "go"
```

_exec_
```text
(integer) 1
(integer) 0
```

Check if element is member of set

- Returns 1 if member, 0 if not
- O(1) operation, very fast

#### Check Multiple Members

```bash
redis-cli SMISMEMBER tags "python" "redis" "go"
```

_exec_
```text
1) (integer) 1
2) (integer) 1
3) (integer) 0
```

Check membership of multiple elements in single command

- Returns array of 1/0 for each element

#### Remove Elements from Set

```bash
redis-cli SREM tags "database" "go"
redis-cli SCARD tags
```

_exec_
```text
(integer) 1
(integer) 2
```

Remove members from set, returns count removed

- Only "database" was removed (exists), "go" returned count 1

#### Get All Set Members

```bash
redis-cli SMEMBERS tags
```

_exec_
```text
1) "python"
2) "redis"
```

Return all members of set (unordered)

- Order is not guaranteed
- Use SCAN for large sets to avoid blocking
- Returns array of members

**Best practices:**

- Use sets for membership testing (fast O(1) lookups)
- Use sets for unique collections (tags, followers, permissions)
- Use SCAN for large sets instead of SMEMBERS
- Batch SADD operations when possible

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Set Operations (Union, Intersection, Difference)

Combine and compare sets

**Keywords:** SINTER, SUNION, SDIFF, SINTERSTORE, SUNIONSTORE, SDIFFSTORE

#### Find Common Elements (Intersection)

```bash
redis-cli SADD users:online "alice" "bob" "charlie"
redis-cli SADD users:premium "bob" "charlie" "dave"
redis-cli SINTER users:online users:premium
```

_exec_
```text
(integer) 3
(integer) 3
1) "bob"
2) "charlie"
```

Find elements common to both sets

- Returns only members in ALL specified sets
- Useful for finding users with multiple properties

#### Combine All Elements (Union)

```bash
redis-cli SUNION users:online users:premium
```

_exec_
```text
1) "alice"
2) "bob"
3) "charlie"
4) "dave"
```

Get all unique members from both sets

- Combines all elements, removes duplicates
- Useful for permissions (any admin OR any moderator)

#### Find Unique Elements (Difference)

```bash
redis-cli SDIFF users:online users:premium
```

_exec_
```text
1) "alice"
```

Find elements in first set but not in others

- Order of sets matter (first set minus others)
- Useful for finding exclusive members

#### Store Operation Result

```bash
redis-cli SINTERSTORE premium-online users:online users:premium
redis-cli SMEMBERS premium-online
```

_exec_
```text
(integer) 2
1) "bob"
2) "charlie"
```

Perform operation and store result in new set

- *STORE variants return count of result elements
- Useful for caching computed results

#### Find Multi-Set Intersection

```bash
redis-cli SADD readers "alice" "bob" "charlie" "dave"
redis-cli SADD writers "bob" "charlie" "eve"
redis-cli SADD editors "charlie" "frank"
redis-cli SINTER readers writers editors
```

_exec_
```text
1) "charlie"
```

Find members in all three sets

- Only "charlie" is in readers AND writers AND editors

**Best practices:**

- Use SINTER for access control (user has all required permissions)
- Use SUNION for OR logic (has role-A OR role-B)
- Use SDIFF to find exclusive items (users who haven't redeemed)
- Use *STORE to cache results of expensive operations

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Set Advanced Operations

Advanced set operations and management

**Keywords:** SPOP, SRANDMEMBER, SMOVE, SSCAN

#### Remove and Return Random Member

```bash
redis-cli SADD lottery-pool "ticket-1" "ticket-2" "ticket-3" "ticket-4" "ticket-5"
redis-cli SPOP lottery-pool
redis-cli SPOP lottery-pool 2
```

_exec_
```text
(integer) 5
"ticket-3"
1) "ticket-1"
2) "ticket-5"
```

Remove and return random element(s) from set

- Single member removes one, with count removes multiple
- Useful for random selection and removal (lottery, queue)

#### Get Random Members Without Removal

```bash
redis-cli SRANDMEMBER users:active
redis-cli SRANDMEMBER users:active 3
```

_exec_
```text
"bob"
1) "alice"
2) "charlie"
3) "bob"
```

Return random members without removing them

- Count can exceed set size (with repetition)
- Negative count allows duplicates

#### Move Member Between Sets

```bash
redis-cli SADD users:online "alice"
redis-cli SMOVE users:online users:offline "alice"
redis-cli SISMEMBER users:online "alice"
redis-cli SISMEMBER users:offline "alice"
```

_exec_
```text
(integer) 1
(integer) 1
(integer) 0
(integer) 1
```

Move member from source set to destination set

- Returns 1 if moved, 0 if not found in source
- Atomic operation

#### Scan Large Set

```bash
redis-cli SSCAN users:active 0 COUNT 50
```

_exec_
```text
1) "2048"
2) 1) "user:1"
   2) "user:2"
   3) "user:3"
```

Iterate through set using cursor without blocking

- Returns [cursor, [members]]
- Use cursor 0 to start, continue until 0 returned

**Best practices:**

- Use SPOP for removing random samples
- Use SRANDMEMBER for sampling without removal
- Use SMOVE for state transitions between sets
- Use SSCAN for large sets instead of SMEMBERS

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

## Hash Operations

### Hash Get and Set Operations

Store and retrieve hash field-value pairs

**Keywords:** HSET, HGET, HMSET, HMGET, HGETALL, HDEL

#### Set and Get Hash Fields

```bash
redis-cli HSET user:1 name "Alice" email "alice@example.com" age "30"
redis-cli HGET user:1 name
redis-cli HGET user:1 email
```

_exec_
```text
(integer) 3
"Alice"
"alice@example.com"
```

Set multiple hash fields and retrieve individual ones

- HSET can set multiple field-value pairs at once
- Returns count of new fields added
- HGET returns nil if field doesn't exist

#### Get Multiple Hash Fields

```bash
redis-cli HMGET user:1 name age country
```

_exec_
```text
1) "Alice"
2) "30"
3) (nil)
```

Retrieve multiple fields in single command

- Returns array with nil for non-existent fields
- More efficient than multiple HGET calls

#### Get All Hash Fields and Values

```bash
redis-cli HGETALL user:1
```

_exec_
```text
1) "name"
2) "Alice"
3) "email"
4) "alice@example.com"
5) "age"
6) "30"
```

Retrieve all field-value pairs from hash

- Returns flattened array [field1, value1, field2, value2, ...]
- For large hashes, use HSCAN to avoid blocking

#### Delete Hash Fields

```bash
redis-cli HDEL user:1 age country
redis-cli HLEN user:1
```

_exec_
```text
(integer) 1
(integer) 2
```

Remove fields from hash, returns count deleted

- "age" was deleted (1), "country" didn't exist (not counted)"
- HLEN shows remaining fields

#### Check Field Existence

```bash
redis-cli HEXISTS user:1 name
redis-cli HEXISTS user:1 age
```

_exec_
```text
(integer) 1
(integer) 0
```

Check if specific field exists in hash

- Returns 1 if exists, 0 if not
- O(1) operation

**Best practices:**

- Use hashes for multi-field objects (user profiles, configs)
- Set multiple fields at once to reduce network calls
- Use HSCAN for large hashes instead of HGETALL
- Structure as hash instead of multiple strings for related data

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Hash Numeric Operations

Increment and perform math on hash fields

**Keywords:** HINCRBY, HINCRBYFLOAT, HSETNX

#### Increment Integer Hash Field

```bash
redis-cli HSET product:1 price 100 stock 50
redis-cli HINCRBY product:1 stock -5
redis-cli HGET product:1 stock
```

_exec_
```text
(integer) 2
(integer) 45
"45"
```

Decrement (negative increment) stock field in hash

- Useful for inventory management
- Returns new value after increment

#### Increment Float Hash Field

```bash
redis-cli HSET stats:page daily-avg 2.5
redis-cli HINCRBYFLOAT stats:page daily-avg 0.3
redis-cli HGET stats:page daily-avg
```

_exec_
```text
(integer) 1
"2.8"
"2.8"
```

Add decimal value to hash field

- Useful for floating point metrics
- Returns new value as string

#### Set Field Only If Doesn't Exist

```bash
redis-cli HSETNX user:profile avatar "default.jpg"
redis-cli HSETNX user:profile avatar "custom.jpg"
```

_exec_
```text
(integer) 1
(integer) 0
```

Set field only if it doesn't already have a value

- Returns 1 if field set, 0 if already existed
- Useful for defaults and initialization

**Best practices:**

- Use HINCRBY for counters in hash fields
- Use HINCRBYFLOAT for averaged metrics
- Use HSETNX to prevent overwriting configured values
- Validate numeric fields before incrementing

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Hash Scanning and Enumeration

Iterate through hash fields without blocking

**Keywords:** HSCAN, HKEYS, HVALS, HLEN, HSTRLEN

#### Get All Hash Field Names

```bash
redis-cli HKEYS user:1
```

_exec_
```text
1) "name"
2) "email"
3) "phone"
```

Return all field names from hash

- Order not guaranteed
- Use HSCAN for large hashes instead

#### Get All Hash Values

```bash
redis-cli HVALS user:1
```

_exec_
```text
1) "Alice"
2) "alice@example.com"
3) "555-1234"
```

Return all values without field names

- Returns array of values only

#### Get Hash Field Count

```bash
redis-cli HLEN user:1
```

_exec_
```text
(integer) 3
```

Count number of fields in hash

- O(1) operation
- Returns 0 for non-existent hash

#### Scan Hash Fields with Pattern

```bash
redis-cli HSCAN config:app 0 MATCH "*-timeout" COUNT 10
```

_exec_
```text
1) "2048"
2) 1) "api-timeout"
   2) "30000"
   3) "db-timeout"
   4) "5000"
```

Scan hash fields matching pattern without blocking

- Returns [cursor, [field1, value1, field2, value2, ...]]
- Cursor-based iteration like SCAN

#### Get String Length of Hash Field Value

```bash
redis-cli HSTRLEN user:1 email
```

_exec_
```text
(integer) 19
```

Return byte length of specific field's value

- Useful for validation without retrieving value

**Best practices:**

- Use HKEYS/HVALS when you know hash is small
- Use HSCAN for large hashes with millions of fields
- Monitor HLEN to detect abnormal growth
- Use field names with consistent prefixes for HSCAN patterns

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

## Sorted Sets Operations

### Sorted Set Add and Remove Operations

Manage sorted set members with scores

**Keywords:** ZADD, ZREM, ZCARD, ZRANGE, ZREVRANGE, ZSCORE

#### Add Members with Scores

```bash
redis-cli ZADD leaderboard 100 "player1" 150 "player2" 120 "player3"
redis-cli ZCARD leaderboard
```

_exec_
```text
(integer) 3
(integer) 3
```

Add members to sorted set with numeric scores

- Members sorted by score in ascending order
- Duplicate members update score

#### Get Range by Index

```bash
redis-cli ZRANGE leaderboard 0 -1
redis-cli ZRANGE leaderboard 0 -1 WITHSCORES
```

_exec_
```text
1) "player1"
2) "player3"
3) "player2"
1) "player1"
2) "100"
3) "player3"
4) "120"
5) "player2"
6) "150"
```

Get members in score order, optionally with scores

- 0 = lowest score, -1 = highest score
- WITHSCORES returns interleaved scores

#### Get Range in Reverse Order

```bash
redis-cli ZREVRANGE leaderboard 0 2 WITHSCORES
```

_exec_
```text
1) "player2"
2) "150"
3) "player3"
4) "120"
5) "player1"
6) "100"
```

Get top scorers in descending order

- ZREVRANGE returns highest scores first
- Perfect for leaderboards

#### Get Member Rank

```bash
redis-cli ZRANK leaderboard "player1"
redis-cli ZREVRANK leaderboard "player1"
```

_exec_
```text
(integer) 0
(integer) 2
```

Get position of member in sorted set

- ZRANK = position from low to high
- ZREVRANK = position from high to low
- 0-indexed

#### Get Member Score

```bash
redis-cli ZSCORE leaderboard "player2"
```

_exec_
```text
"150"
```

Retrieve score of specific member

- Returns nil if member doesn't exist

#### Remove Members

```bash
redis-cli ZREM leaderboard "player3" "nonexistent"
redis-cli ZCARD leaderboard
```

_exec_
```text
(integer) 1
(integer) 2
```

Remove members from sorted set

- Returns count of actually removed members

**Best practices:**

- Use sorted sets for leaderboards, rankings, scored data
- Use ZREVRANGE 0 n-1 for top-N queries
- Batch ZADD operations to reduce round trips
- Monitor ZCARD to detect unusual growth

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Sorted Set Range Queries

Query sorted sets by score or lexicographical range

**Keywords:** ZRANGEBYSCORE, ZREVRANGEBYSCORE, ZRANGEBYLEX, ZCOUNT, ZLEXCOUNT

#### Get Members in Score Range

```bash
redis-cli ZADD product-scores 8.2 "item-1" 7.5 "item-2" 9.1 "item-3" 6.8 "item-4"
redis-cli ZRANGEBYSCORE product-scores 7 9 WITHSCORES
```

_exec_
```text
1) "item-2"
2) "7.5"
3) "item-1"
4) "8.2"
5) "item-3"
6) "9.1"
```

Get all members with scores in range [7, 9]

- Inclusive range by default
- Use (score for exclusive range

#### Query with Score Limits

```bash
redis-cli ZRANGEBYSCORE product-scores 7 (9 LIMIT 0 2
```

_exec_
```text
1) "item-2"
2) "item-1"
```

Get range with exclusive upper bound and pagination

- (9 means score < 9 (exclusive)
- LIMIT offset count for pagination

#### Get All Members with Minimum Score

```bash
redis-cli ZRANGEBYSCORE product-scores 8 +inf
```

_exec_
```text
1) "item-1"
2) "item-3"
```

Use +inf for scores greater than value

- -inf for minimum scores
- inf without + means non-existent

#### Count Members in Score Range

```bash
redis-cli ZCOUNT product-scores 7 9
```

_exec_
```text
(integer) 3
```

Count members without retrieving them

- Returns count of members in range
- O(log n) operation

#### Lexicographical Range (Members with Equal Scores)

```bash
redis-cli ZADD colors 0 "black" 0 "blue" 0 "green" 0 "red"
redis-cli ZRANGEBYLEX colors "[b" "[g"
```

_exec_
```text
1) "black"
2) "blue"
3) "green"
```

Query members lexicographically when scores are equal

- All members must have same score
- "[" = inclusive, "(" = exclusive boundary

**Best practices:**

- Use ZRANGEBYSCORE for score-based filtering (ratings > 4.0)
- Use ZCOUNT to quickly find count of items in range
- Combine with LIMIT for pagination of large ranges
- Use ZRANGEBYLEX for alphabetical listings

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Sorted Set Increment Operations

Modify scores and manage sorted set members

**Keywords:** ZINCRBY, ZPOPMIN, ZPOPMAX, BZPOPMIN, BZPOPMAX

#### Increment Member Score

```bash
redis-cli ZADD ratings user:1 4.5
redis-cli ZINCRBY ratings 0.5 user:1
redis-cli ZSCORE ratings user:1
```

_exec_
```text
(integer) 1
"5"
"5"
```

Increase score of member, returns new score

- Negative value decreases score
- Creates member if doesn't exist

#### Pop Lowest Scoring Member

```bash
redis-cli ZPOPMIN priority-queue 2
```

_exec_
```text
1) "task-1"
2) "1"
3) "task-2"
4) "2"
```

Remove and return lowest scoring members

- Returns [member1, score1, member2, score2, ...]
- Useful for processing queues by priority

#### Pop Highest Scoring Member

```bash
redis-cli ZPOPMAX leaderboard 1
```

_exec_
```text
1) "player2"
2) "150"
```

Remove and return highest scoring members

- Opposite of ZPOPMIN

#### Blocking Pop Operations

```bash
redis-cli BZPOPMIN priority:queue 0
```

_exec_
```text
1) "priority:queue"
2) "item-id"
3) "1"
```

Block until lowest score member available

- Returns [key, member, score] on timeout nil
- Useful for task processing

**Best practices:**

- Use ZINCRBY to update scores atomically
- Use ZPOPMIN for processing by priority
- Use BZPOPMIN for worker processes
- Validate score updates don't cause data anomalies

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

## Transactions & Scripting

### Transaction Basics

Execute commands atomically with MULTI and EXEC

**Keywords:** MULTI, EXEC, DISCARD, WATCH, atomic operations

#### Simple Transaction

```bash
redis-cli
127.0.0.1:6379> MULTI
127.0.0.1:6379> SET key1 "value1"
127.0.0.1:6379> SET key2 "value2"
127.0.0.1:6379> GET key1
127.0.0.1:6379> EXEC
```

_exec_
```text
OK
QUEUED
QUEUED
QUEUED
1) OK
2) OK
3) "value1"
```

Queue commands and execute atomically

- Commands return QUEUED when in transaction
- EXEC returns array of results
- All commands execute or none if error

#### Cancel Transaction

```bash
redis-cli
127.0.0.1:6379> MULTI
127.0.0.1:6379> SET key1 "value"
127.0.0.1:6379> DISCARD
127.0.0.1:6379> GET key1
```

_exec_
```text
OK
QUEUED
OK
(nil)
```

Cancel transaction without executing queued commands

- DISCARD returns OK
- All queued commands are discarded

#### Monitor Key and Abort on Change

```bash
redis-cli
127.0.0.1:6379> SET account:1:balance "1000"
127.0.0.1:6379> WATCH account:1:balance
127.0.0.1:6379> MULTI
127.0.0.1:6379> DECRBY account:1:balance 100
127.0.0.1:6379> EXEC
```

_exec_
```text
OK
OK
OK
QUEUED
1) (integer) 900
```

Monitor key and only execute if unchanged

- If key changed between WATCH and EXEC, transaction aborts
- Returns nil if transaction aborted

#### Optimistic Lock with WATCH

```bash
redis-cli WATCH mykey
value=$(redis-cli GET mykey)
# ... check value in application ...
redis-cli MULTI
redis-cli SET mykey "newvalue"
# ... other commands ...
redis-cli EXEC
```

_exec_
```text
OK
"oldvalue"
OK
QUEUED
1) OK
```

Implement optimistic locking pattern

- Application decides whether to commit
- Useful for non-critical updates

**Best practices:**

- Use transactions for related operations that must happen together
- Keep transactions short to minimize lock contention
- Use WATCH for optimistic locking on critical data
- Handle nil return from EXEC (transaction aborted)

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Lua Scripting

Execute Lua scripts atomically on server

**Keywords:** EVAL, EVALSHA, SCRIPT LOAD, SCRIPT FLUSH, atomic Lua execution

#### Execute Simple Lua Script

```bash
redis-cli EVAL "return 'Hello from Lua'" 0
```

_exec_
```text
"Hello from Lua"
```

Execute inline Lua script with zero keys

- "0" = number of key arguments following
- Script returns result to client

#### Lua Script with Key and Argument

```bash
redis-cli EVAL "return redis.call('GET', KEYS[1])" 1 mykey
```

_exec_
```text
"value"
```

Access Redis keys from Lua script

- KEYS[1] = first key argument
- ARGV indexing starts at 1 (not 0)

#### Increment with Constraint

```bash
redis-cli EVAL "
local current = redis.call('GET', KEYS[1])
if tonumber(current) < tonumber(ARGV[1]) then
  redis.call('INCR', KEYS[1])
  return 1
end
return 0
" 1 counter 100
```

_exec_
```text
(integer) 1
```

Conditional increment only if under limit

- Atomic constraint check and update
- Returns 1 if incremented, 0 if limit reached

#### Preload Script with SHA

```bash
redis-cli SCRIPT LOAD "return 'cached script'"
# Save SHA returned: abc123...
redis-cli EVALSHA abc123... 0
```

_exec_
```text
"abc123def456..."
"cached script"
```

Load script once, execute many times by SHA

- Reduces bandwidth for frequently used scripts
- More efficient than EVAL for repeated calls

#### Script Management

```bash
redis-cli SCRIPT EXISTS sha1 sha2 sha3
redis-cli SCRIPT FLUSH
redis-cli SCRIPT KILL
```

_exec_
```text
1) (integer) 1
2) (integer) 0
(integer) 3
OK
```

Check script existence, clear cache, terminate running

- SCRIPT EXISTS returns array of 1/0 for each SHA
- SCRIPT FLUSH clears script cache (careful in production!)

**Best practices:**

- Use Lua for atomic operations combining multiple commands
- Preload scripts with SCRIPT LOAD for frequent use
- Keep scripts focused and simple for maintainability
- Use EVALSHA after preloading to reduce network traffic

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

## Pub/Sub & Streams

### Pub/Sub Basics

Publish and subscribe to message channels

**Keywords:** PUBLISH, SUBSCRIBE, UNSUBSCRIBE, message broadcast, channels

#### Subscribe to Channel

```bash
# Terminal 1
redis-cli
127.0.0.1:6379> SUBSCRIBE news
```

_exec_
```text
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "news"
3) (integer) 1
```

Subscribe to "news" channel and wait for messages

- Client blocks in subscribe mode
- Receives confirmation message with subscription count

#### Publish Message

```bash
# Terminal 2
redis-cli PUBLISH news "Breaking news!"
```

_exec_
```text
(integer) 1
```

Publish message to channel

- Returns number of subscribers that received message
- Message sent immediately to all subscribers

#### Receive Published Message

```bash
# Terminal 1 receiving
```

_exec_
```text
1) "message"
2) "news"
3) "Breaking news!"
```

Subscriber receives published message

- Array format [type, channel, message]
- Continues waiting for more messages

#### Subscribe to Multiple Channels

```bash
redis-cli
127.0.0.1:6379> SUBSCRIBE sports weather cryptocurrency
```

_exec_
```text
Reading messages...
1) "subscribe"
2) "sports"
3) (integer) 1
1) "subscribe"
2) "weather"
3) (integer) 2
1) "subscribe"
2) "cryptocurrency"
3) (integer) 3
```

Subscribe to multiple channels at once

- Subscription count increases per channel
- Client receives messages from any subscribed channel

#### Pattern Subscription

```bash
redis-cli PSUBSCRIBE "user:*:notification"
```

_exec_
```text
1) "psubscribe"
2) "user:*:notification"
3) (integer) 1
```

Subscribe to channels matching pattern

- Receives messages from matching dynamic channels
- Pattern matching on server side

**Best practices:**

- Use pub/sub for real-time notifications, not persistent queues
- Publish count indicates delivery, but no guarantee of processing
- Combine with persistence (streams) for critical messages
- Use pattern subscriptions for dynamic channel names

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Redis Streams

Persistent, ordered message queues

**Keywords:** XADD, XREAD, XRANGE, XGROUP, stream consumer groups

#### Add Message to Stream

```bash
redis-cli XADD events "*" type "user_login" user "alice" ip "192.168.1.1"
redis-cli XADD events "*" type "user_logout" user "bob"
```

_exec_
```text
"1704067200000-0"
"1704067201000-0"
```

Add messages to stream with auto-generated timestamp ID

- "*" = auto-generate ID from milliseconds
- ID format = timestamp-sequence

#### Read Stream Range

```bash
redis-cli XRANGE events - +
```

_exec_
```text
1) 1) "1704067200000-0"
   2) 1) "type"
      2) "user_login"
      3) "user"
      4) "alice"
      5) "ip"
      6) "192.168.1.1"
2) 1) "1704067201000-0"
   2) 1) "type"
      2) "user_logout"
      3) "user"
      4) "bob"
```

Read all messages in stream (oldest to newest)

- "-" = minimum ID, "+" = maximum ID
- Returns all messages with data

#### Read New Messages from Position

```bash
redis-cli XREAD COUNT 2 STREAMS events "1704067200000-0"
```

_exec_
```text
1) 1) "events"
   2) 1) 1) "1704067201000-0"
      2) 1) "type"
         2) "user_logout"
```

Read new messages after specific position

- Returns messages after provided ID
- COUNT limits returned messages

#### Create Consumer Group

```bash
redis-cli XGROUP CREATE events mygroup 0
redis-cli XREADGROUP GROUP mygroup consumer1 STREAMS events ">"
```

_exec_
```text
OK
1) 1) "events"
   2) 1) 1) "1704067200000-0"
      2) 1) "type"
         2) "user_login"
```

Create processor group and read undelivered messages

- "0" = start from beginning
- ">" = new messages not yet delivered

#### Acknowledge Message Processing

```bash
redis-cli XACK events mygroup "1704067200000-0"
redis-cli XPENDING events mygroup
```

_exec_
```text
(integer) 1
1) (integer) 0
   2) "1704067201000-0"
   3) "1704067201000-0"
   4) 1) 1) "consumer1"
      2) (integer) 1
```

Acknowledge processed message and check pending

- XACK removes from pending list
- XPENDING shows unacknowledged messages

**Best practices:**

- Use streams for persistent, ordered message queues
- Use consumer groups for distributed message processing
- Acknowledge messages after processing to track progress
- Monitor pending messages to detect stuck consumers

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

## Advanced Features

### Persistence (RDB and AOF)

Save and restore Redis data with RDB snapshots and AOF logs

**Keywords:** SAVE, BGSAVE, BGREWRITEAOF, persistence modes, data durability

#### Manual RDB Snapshot

```bash
redis-cli SAVE
```

_exec_
```text
OK
```

Create RDB snapshot synchronously (blocks server)

- Blocking operation, avoid in production
- Saves to dump.rdb file

#### Background RDB Snapshot

```bash
redis-cli BGSAVE
```

_exec_
```text
Background saving started
```

Trigger RDB snapshot in background thread

- Non-blocking, server continues operations
- Check LASTSAVE for completion

#### Check Last Save Time

```bash
redis-cli LASTSAVE
```

_exec_
```text
(integer) 1704067890
```

Get Unix timestamp of last successful RDB save

- Returns seconds since epoch
- Useful for monitoring backup freshness

#### Rewrite AOF Log

```bash
redis-cli BGREWRITEAOF
```

_exec_
```text
Background append only file rewriting started
```

Trigger AOF log compaction in background

- Reduces AOF file size by removing redundant commands
- Non-blocking operation

**Best practices:**

- Use AOF for critical data requiring durability
- Use RDB for snapshots and faster recovery
- Enable both for maximum protection
- Monitor disk space used by persistence files

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Replication and Clustering

Set up master-replica replication and Redis Cluster

**Keywords:** REPLICAOF, replication, master-replica, cluster nodes, failover

#### Configure Replica

```bash
redis-cli REPLICAOF master-host 6379
redis-cli INFO replication
```

_exec_
```text
OK
# Replication
role:slave
master_host:master-host
master_port:6379
master_link_status:up
master_repl_offset:1234567
```

Configure server as replica of master

- Starts syncing from master
- Receives all write commands from master

#### Stop Replication

```bash
redis-cli REPLICAOF NO ONE
```

_exec_
```text
OK
```

Stop replication and become standalone master

- Keeps data already synced
- Stops receiving updates from old master

#### Check Replica Lag

```bash
redis-cli INFO replication | grep master_repl_offset
```

_exec_
```text
master_repl_offset:9876543
```

Monitor master replication offset

- Indicates how much data replica has from master

#### Cluster Info

```bash
redis-cli CLUSTER INFO
```

_exec_
```text
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
```

Check Redis Cluster status

- Shows slot distribution and health

**Best practices:**

- Use replication for high availability
- Monitor replication lag to detect issues
- Test failover procedures regularly
- Use cluster for automatic sharding at scale

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined

### Memory Optimization

Monitor and optimize Redis memory usage

**Keywords:** memory management, eviction policies, maxmemory, key expiration, memory stats

#### Check Memory Stats

```bash
redis-cli INFO memory
```

_exec_
```text
# Memory
used_memory:1048576
used_memory_human:1.00M
used_memory_rss:2097152
used_memory_rss_human:2.00M
allocator_active:1572864
allocator_allocated:1048576
used_memory_peak:1100000
used_memory_peak_human:1.05M
```

Get detailed memory usage breakdown

- used_memory = Redis internal memory
- used_memory_rss = OS allocated memory (higher due to fragmentation)

#### Set Memory Limit

```bash
redis-cli CONFIG SET maxmemory 2147483648
redis-cli CONFIG SET maxmemory-policy allkeys-lru
```

_exec_
```text
OK
OK
```

Set max memory to 2GB with LRU eviction policy

- Policies: noeviction, allkeys-lru, volatile-lru, allkeys-random, etc.
- allkeys-lru = evict any key using LRU

#### Eviction Policy Behavior

```bash
# When maxmemory reached with volatile-lru:
# Evicts keys with expiration, using LRU algorithm
```

_exec_
```text
# Only keys with TTL are eligible
# LRU tracks least recently used
```

Understand volatile-lru eviction

- Applies only to keys with EXPIRE set
- Safer than allkeys as it preserves important data

#### Analyze Key Memory Usage

```bash
redis-cli --ldb
# Alternative: MEMORY DOCTOR command
redis-cli MEMORY DOCTOR
```

_exec_
```text
Sam, I'm sorry. I don't see much to worry about...
# or detailed advice about memory issues
```

Get Redis memory analysis and recommendations

- Provides optimization suggestions
- Shows potential memory leaks

**Best practices:**

- Monitor used_memory/used_memory_rss ratio for fragmentation
- Set maxmemory-policy based on use case
- Use volatile-lru for cache-like data
- Use noeviction for critical non-expiring data

**Common errors:**

- **undefined**: undefined
- **undefined**: undefined
