Redis Lists
Lists are linked lists of string values, supporting push/pop operations from both ends in O(1) time. They're ideal for queues, stacks, activity feeds, and any scenario requiring ordered data with fast insertion.
When Redis Lists Are the Right Choice
Choose Redis lists when insertion order matters and you mainly push or pop from the ends. They work well for simple worker queues, recent activity feeds, undo stacks, and capped message buffers.
Key Characteristics
• Maximum length: 2^32 - 1 elements (over 4 billion) • O(1) push/pop at head or tail • O(N) access by index (linked list behavior) • Supports blocking operations for pub/sub patterns
Basic Push/Pop Operations
# Push to list
RPUSH queue:jobs "job1" "job2" "job3" # Add to right (tail)
LPUSH queue:jobs "job0" # Add to left (head)
# Pop from list
RPOP queue:jobs # Remove from right → "job3"
LPOP queue:jobs # Remove from left → "job0"
# Pop multiple
LPOP queue:jobs 2 # Pop 2 from left
RPOP queue:jobs 3 # Pop 3 from rightRange Operations
LRANGE queue:jobs 0 -1 # Get all elements
LRANGE queue:jobs 0 2 # Get first 3 elements
LRANGE queue:jobs -3 -1 # Get last 3 elements
LLEN queue:jobs # Get list lengthQueue Pattern (FIFO)
First In, First Out: add to tail, remove from head.
# Enqueue
RPUSH queue:tasks "task1"
RPUSH queue:tasks "task2"
RPUSH queue:tasks "task3"
# Dequeue
LPOP queue:tasks # → "task1"
LPOP queue:tasks # → "task2"Stack Pattern (LIFO)
Last In, First Out: add to head, remove from head.
# Push
LPUSH stack:undo "action1"
LPUSH stack:undo "action2"
LPUSH stack:undo "action3"
# Pop
LPOP stack:undo # → "action3"
LPOP stack:undo # → "action2"Blocking Operations
Block until an element is available—perfect for worker queues.
# Block up to 30 seconds for an item
BRPOP queue:jobs 30
# Block on multiple queues (priority order)
BLPOP queue:priority queue:normal 0 # 0 = block forever
# Block and move atomically
BLMOVE source dest LEFT RIGHT 30 # Move with 30s timeoutIndex Operations
LINDEX queue:jobs 0 # Get element at index
LINDEX queue:jobs -1 # Get last element
LSET queue:jobs 0 "updated_job" # Update element at index
LPOS queue:jobs "target_value" # Find position of valueInsert and Remove
# Insert relative to element
LINSERT queue:jobs BEFORE "job2" "job1.5"
LINSERT queue:jobs AFTER "job2" "job2.5"
# Remove occurrences
LREM queue:jobs 1 "job1" # Remove 1 occurrence
LREM queue:jobs 0 "job1" # Remove all occurrences
LREM queue:jobs -2 "job1" # Remove 2 from tailTrimming
Keep only a range of elements—perfect for capped collections.
# Keep only last 100 notifications
LPUSH notifications:user:1 "new notification"
LTRIM notifications:user:1 0 99
# Activity feed with automatic capping
def add_activity(user_id, activity):
key = f"feed:user:{user_id}"
LPUSH(key, activity)
LTRIM(key, 0, 999) # Keep only 1000 most recentMoving Between Lists
# Atomically move element between lists
LMOVE source dest LEFT RIGHT # Pop from source left, push to dest right
LMOVE source dest RIGHT LEFT # Pop from source right, push to dest left
# Rotate within same list
LMOVE mylist mylist LEFT RIGHT # Move head to tailUse Case: Reliable Queue
Use LMOVE for reliable processing with acknowledgment.
# Producer
RPUSH queue:pending "job_data"
# Worker
while True:
# Move job to processing list atomically
job = LMOVE queue:pending queue:processing RIGHT LEFT
if job:
try:
process(job)
# Remove from processing on success
LREM queue:processing 1 job
except Exception:
# Re-queue on failure
LMOVE queue:processing queue:pending LEFT RIGHTUse Case: Recent Activity Feed
def add_activity(user_id, activity_json):
key = f"activity:{user_id}"
# Add to feed
LPUSH(key, activity_json)
# Keep only last 50 items
LTRIM(key, 0, 49)
# Optional: set expiration for inactive users
EXPIRE(key, 86400 * 30) # 30 days
def get_recent_activity(user_id, count=20):
key = f"activity:{user_id}"
return LRANGE(key, 0, count - 1)Common Redis List Mistakes
A common mistake is using lists as a general random-access array. Redis lists are optimized for the ends, not arbitrary index reads or updates, so performance drops if the workload constantly pokes the middle of long lists.
Related
Compare lists with streams, sets, and zsets before choosing a queue or feed model.
Use streams when a simple list queue grows into consumer groups and replay requirements.
Switch to sorted sets when ordered items need explicit ranking or timestamp scores.
Useful when list-based queues feed scheduled workers or recurring jobs.