Redis Lists (Part 1)
A list is an ordered, repeatable sequence of strings. This lesson covers basic list operations.
What is a List?
A list is similar to:
- Python's list
- JavaScript's Array
- Java's LinkedList
Redis list features:
- Ordered: elements maintain insertion order
- Repeatable: the same value can appear multiple times
- Dual-ended operations: insert and pop from both ends
mylist
├─ "element1"
├─ "element2"
├─ "element3"
└─ "element4"
💡 Internal implementation: Redis lists use quicklist, a combination of doubly-linked list and ziplist that balances memory and performance.
LPUSH and RPUSH: Insert Elements
LPUSH: Insert from the Left (Head)
REDIS
# Insert a single element from the left
LPUSH mylist "world"
(integer) 1 # Returns list length
# Insert multiple elements from the left
LPUSH mylist "hello"
(integer) 2
# View the list
LRANGE mylist 0 -1
1) "hello"
2) "world"
⚠️ Note: When inserting multiple elements with LPUSH, they are inserted left-to-right in parameter order.
LPUSH mylist a b c results in [c, b, a, ...].
RPUSH: Insert from the Right (Tail)
REDIS
# Insert from the right
RPUSH mylist "Redis"
(integer) 3
RPUSH mylist "Tutorial"
(integer) 4
# View the list
LRANGE mylist 0 -1
1) "hello"
2) "world"
3) "Redis"
4) "Tutorial"
LPUSHX and RPUSHX: Insert Only if List Exists
REDIS
# Insert fails when list does not exist
LPUSHX notexist "value"
(integer) 0
# Insert succeeds when list exists
LPUSHX mylist "first"
(integer) 5
RPUSHX mylist "last"
(integer) 6
LPOP and RPOP: Pop Elements
LPOP: Pop from the Left (Head)
REDIS
# View current list
LRANGE mylist 0 -1
1) "first"
2) "hello"
3) "world"
4) "Redis"
5) "Tutorial"
6) "last"
# Pop from the left
LPOP mylist
"first"
# Pop multiple elements (Redis 6.2+)
LPOP mylist 2
1) "hello"
2) "world"
RPOP: Pop from the Right (Tail)
REDIS
# Pop from the right
RPOP mylist
"last"
# Pop multiple elements (Redis 6.2+)
RPOP mylist 2
1) "Tutorial"
2) "Redis"
When List is Empty
REDIS
LPOP emptylist
(nil) # Returns nil for empty list
LLEN: Get List Length
REDIS
LPUSH mylist "a" "b" "c"
LLEN mylist
(integer) 3
# List does not exist
LLEN notexist
(integer) 0
LRANGE: Get Elements Within a Range
LRANGE is the most common list query command.
Basic Usage
REDIS
LPUSH mylist "one" "two" "three" "four" "five"
# Get all elements
LRANGE mylist 0 -1
1) "five"
2) "four"
3) "three"
4) "two"
5) "one"
# Get first 3 elements
LRANGE mylist 0 2
1) "five"
2) "four"
3) "three"
# Get last 2 elements
LRANGE mylist -2 -1
1) "two"
2) "one"
# Get elements at index 1 through 3
LRANGE mylist 1 3
1) "four"
2) "three"
3) "two"
Index Rules
| Index | Description |
|---|---|
| 0 | First element |
| 1 | Second element |
| -1 | Last element |
| -2 | Second to last element |
| 0 -1 | All elements |
⚠️ Note: The end index in LRANGE is inclusive.
LRANGE 0 2 returns elements at indexes 0, 1, 2 (3 elements total).
Implementing Queues and Stacks with Lists
Queue (FIFO: First In, First Out)
Using RPUSH + LPOP:
REDIS
# Producer: enqueue from the right
RPUSH queue:task "task1"
RPUSH queue:task "task2"
RPUSH queue:task "task3"
# Consumer: dequeue from the left
LPOP queue:task
"task1"
LPOP queue:task
"task2"
Enqueue → [task1, task2, task3] → Dequeue
RPUSH LPOP
Stack (LIFO: Last In, First Out)
Using LPUSH + LPOP:
REDIS
# Push
LPUSH stack:data "item1"
LPUSH stack:data "item2"
LPUSH stack:data "item3"
# Pop
LPOP stack:data
"item3"
LPOP stack:data
"item2"
Push → [item3, item2, item1] → Pop
LPUSH LPOP
💡 Memory aid:
- Queue: RPUSH + LPOP (right in, left out)
- Stack: LPUSH + LPOP (left in, left out)
Blocking Pop: BLPOP and BRPOP
When the list is empty, BLPOP and BRPOP block until an element is available or a timeout occurs.
BLPOP: Blocking Left Pop
REDIS
# Client 1: wait for a task in the queue (max 10 seconds)
BLPOP queue:task 10
# Client 2: add a task
RPUSH queue:task "new_task"
# Client 1 receives:
1) "queue:task" # List name
2) "new_task" # Popped element
BRPOP: Blocking Right Pop
REDIS
BRPOP queue:task 10
Blocking on Multiple Lists
REDIS
# Wait on multiple lists, return whichever has data first
BLPOP queue:high queue:low 10
💡 Use case: BLPOP/BRPOP are commonly used for implementing task queues and message queues, where consumers block waiting for new tasks.
List Use Cases
Use Case 1: Message Queue
REDIS
# Producer: send a message
RPUSH queue:email '{"to":"user@example.com","subject":"Hello"}'
# Consumer: receive a message (blocking wait)
BLPOP queue:email 0
Use Case 2: Recent List
REDIS
# Add latest articles
LPUSH articles:latest "article:123"
LPUSH articles:latest "article:124"
LPUSH articles:latest "article:125"
# Get latest 10 articles
LRANGE articles:latest 0 9
# Keep the list at most 100 articles
LTRIM articles:latest 0 99
Use Case 3: Timeline
REDIS
# Publish a post (add to user timeline)
LPUSH timeline:user:1 "post:1001"
LPUSH timeline:user:1 "post:1002"
# View timeline (latest 20 posts)
LRANGE timeline:user:1 0 19
Use Case 4: Operation Log
REDIS
# Record user actions
RPUSH log:user:1 "login at 2026-06-23 10:00:00"
RPUSH log:user:1 "view article:123"
RPUSH log:user:1 "like article:123"
# View recent actions
LRANGE log:user:1 -10 -1
LTRIM: Trim the List
LTRIM retains elements within a specified range and deletes everything else.
REDIS
LPUSH mylist "one" "two" "three" "four" "five"
# Keep only the first 3 elements
LTRIM mylist 0 2
OK
LRANGE mylist 0 -1
1) "five"
2) "four"
3) "three"
Use Case: Maintain a Fixed-Size List
REDIS
# Add a new article and keep at most 100
LPUSH articles:latest "article:new"
LTRIM articles:latest 0 99
💡 Tip: LPUSH + LTRIM together maintain a capped list of the latest items.
❓ FAQ
Q What is the maximum number of elements in a list?
A Up to 2^32 - 1 (about 4.2 billion), but practically limited by memory.
Q How fast are LPUSH and RPOP?
A O(1) time complexity — very fast. Head and tail operations are constant time.
Q How fast is LRANGE?
A O(N), where N is the number of returned elements. Getting a large range is slower.
Q Does BLPOP block indefinitely?
A No. Set a timeout; after the timeout, it returns nil. A timeout of 0 means wait forever.
Q What about inserting in the middle of a list?
A Use LINSERT, but it has O(N) performance. It's recommended to only operate at the head and tail.
📖 Summary
- List is an ordered, repeatable string sequence
- LPUSH/RPUSH insert from left and right, LPOP/RPOP pop from left and right
- LRANGE gets elements within a range, LLEN gets the length
- RPUSH + LPOP = Queue (FIFO)
- LPUSH + LPOP = Stack (LIFO)
- BLPOP/BRPOP blocking pop, used for task queues
- List applications: message queues, recent lists, timelines, operation logs
- LTRIM trims the list to maintain a fixed size
📝 Exercises
- Queue implementation: Use RPUSH and LPOP to implement a task queue, simulating a producer and consumer
- Stack implementation: Use LPUSH and LPOP to implement a stack, simulating push and pop
- Recent list: Implement a recent articles list, adding articles and keeping at most 10
- Blocking wait: Use BLPOP to implement a blocking task queue (needs two terminals)
Next Lesson
In the next lesson, we will learn Redis Lists (Part 2), covering query, modification, and advanced list operations.



