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.
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)Knowledge is power.