Understand list-end orientation, bounded ranges, trimming, and the operational limits of an ordered Redis sequence.

Lists: LPUSH/RPUSH, LPOP/RPOP, LRANGE, LTRIM, and Ordered Sequence Semantics

Choose hashes, Redis JSON, or many keys from structure, update/query patterns, expiration granularity, memory/cardinality, indexing, ACL boundaries, and migration evidence.

Beginner → Intermediate125–155 minutesOrdered list + bounded-history labRedis Open Source 8.10.1Free/local-firstLast reviewed: September 6, 2026

Learning outcomes

AtlasMart needs a compact recent-activity feed for each store: the feed must preserve arrival order, let an operator inspect a bounded window, and occasionally remove work from either end. A Redis List is an ordered sequence of binary-safe string elements. “Left” means the list head and “right” means the tail; that orientation is part of the API, not merely presentation.

01

Predict the exact order produced by LPUSH, RPUSH, LPOP, and RPOP, including multi-element pushes.

02

Use LRANGE and negative indexes without turning full-list reads into an unbounded production habit.

03

Use LTRIM to keep a bounded recent-history list and explain what it removes.

04

Relate LLEN, response size, command complexity, persistence, replication, and hot-key behavior to production cost.

05

Distinguish an ordered list from a durable/replayable messaging system before using it as a queue.

Exact lab baseline

All Chapter 05 mandatory labs reuse the disposable Chapter 01 environment: Redis Open Source 8.10.1 from Docker Official Image redis:8.10.1, container atlasmart-redis-ch01, standalone topology, host publication 127.0.0.1:6379, TLS disabled only because traffic stays on loopback, default ACL user disabled, named ACL users atlasmart-app and academy-admin, logical database 0, AOF with appendfsync everysec plus RDB snapshots, persistent /data volume, and no explicit Redis maxmemory limit or eviction policy. The application ACL is restricted to ~atlasmart:* and normal read/write/connection categories. The primary interface is the redis-cli shipped in the same 8.10.1 image, so server and CLI versions stay aligned. Mandatory examples use only bounded synthetic keys under atlasmart:ch05:*.

1. Head and tail are semantic choices

LPUSH prepends elements at the left/head. RPUSH appends at the right/tail. LPOP removes from the left; RPOP removes from the right. A FIFO queue can therefore use RPUSH + LPOP, while another equally valid orientation is LPUSH + RPOP. Pick one convention and write it down; mixing conventions silently reverses work.

Producer Consumer Observed order Use
RPUSH LPOP oldest first simple FIFO
LPUSH RPOP oldest first simple FIFO, opposite orientation
LPUSH LPOP newest first stack/LIFO
RPUSH RPOP newest first stack/LIFO
redis-cli · prove list orientation
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:recentdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app RPUSH atlasmart:ch05:recent order:1001 order:1002 order:1003docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LRANGE atlasmart:ch05:recent 0 -1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LPUSH atlasmart:ch05:recent urgent:9001docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LRANGE atlasmart:ch05:recent 0 -1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LPOP atlasmart:ch05:recentdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app RPOP atlasmart:ch05:recentdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LRANGE atlasmart:ch05:recent 0 -1

Expected final list: order:1001, order:1002. The intermediate outputs prove which end each command touches; they do not prove anything about end-to-end job processing.

2. Multi-element pushes can surprise you

When several elements are passed to LPUSH, Redis inserts them at the head in argument order, so the last argument becomes the new first element. That is observable and frequently misread in shell examples.

redis-cli · multi-element push boundary
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:multidocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LPUSH atlasmart:ch05:multi a b cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LRANGE atlasmart:ch05:multi 0 -1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:multidocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app RPUSH atlasmart:ch05:multi a b cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LRANGE atlasmart:ch05:multi 0 -1

The first list reads c b a; the second reads a b c. A batch API that changes from repeated single pushes to one variadic push must preserve the application's intended order explicitly.

3. LRANGE is inclusive, supports negative indexes, and still returns bytes

LRANGE key start stop includes both endpoints. 0 -1 means the entire list; -3 -1 means the last three elements. Convenient does not mean cheap: the command must locate the requested range and return every selected element over the network. A full LRANGE 0 -1 against a very large hot list can increase server work, response bytes, client memory, and tail latency.

redis-cli · bounded range evidence
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:historydocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app RPUSH atlasmart:ch05:history e1 e2 e3 e4 e5 e6docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LLEN atlasmart:ch05:historydocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LRANGE atlasmart:ch05:history 0 2docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LRANGE atlasmart:ch05:history -3 -1

LLEN gives cardinality without transferring the list. In production APIs, prefer a bounded contract such as “latest 50” and measure reply sizes rather than making “all items” the default.

4. LTRIM keeps a range and discards the rest

LTRIM keeps only the specified inclusive range. This makes an ordered, bounded recent-history pattern possible: push a new element, then trim to the window. The commands are individually atomic; if your correctness requires the pair to be indivisible, later transaction/function lessons explain how to combine operations safely.

redis-cli · bounded recent history
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:recent-ordersdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LPUSH atlasmart:ch05:recent-orders order:1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LPUSH atlasmart:ch05:recent-orders order:2docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LPUSH atlasmart:ch05:recent-orders order:3docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LPUSH atlasmart:ch05:recent-orders order:4docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LTRIM atlasmart:ch05:recent-orders 0 2docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LRANGE atlasmart:ch05:recent-orders 0 -1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LLEN atlasmart:ch05:recent-orders

The retained sequence should be order:4 order:3 order:2. This bounds list length, but it does not create a compliance archive: trimmed elements are gone from the logical list.

5. Deliberately wrong: an unbounded “show everything” endpoint

A tempting endpoint is LRANGE atlasmart:orders 0 -1. It works in development and then degrades as the list grows. The mechanism is straightforward: Redis must traverse/return the requested elements, serialize the reply, send it, and the client must allocate/decode it. Persistence does not mitigate that request-time cost.

Controlled failure injection

Do not create millions of elements merely to prove a point. The lab uses 5,000 short synthetic entries, compares a bounded range with the full reply, then deletes only the chapter key. On your machine, measure wall-clock time and response bytes rather than copying any timing from this lesson.

shell · bounded synthetic growth
# Bash, PowerShell, or another shell can generate fixtures; below uses redis-cli --pipe inside the Linux container.docker exec -i atlasmart-redis-ch01 sh -lc 'for i in $(seq 1 5000); do echo "RPUSH atlasmart:ch05:bounded item:$i"; done | REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 redis-cli --user atlasmart-app --pipe'docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LLEN atlasmart:ch05:boundeddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LRANGE atlasmart:ch05:bounded 0 49# Full-range retrieval is shown as the unsafe pattern; do not make it an API default.docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:bounded

The repair is a bounded API, explicit retention, and observability for list length and response size. If the use case needs durable replay, consumer state, or independent readers, a Stream is a better semantic starting point than simply allowing the list to grow forever.

6. Memory, persistence, replication, and Cluster boundaries

A list is one Redis key containing many elements. That can reduce top-level key cardinality, but it can also create a hot key: many clients contend on one key and one Cluster hash slot. AOF/RDB persistence can recover list state according to their configured durability windows, but they do not make an application workflow exactly-once. Redis replication is asynchronous, so a failover can have a different acknowledged-write boundary than the client assumes unless the architecture is designed and tested around it.

List operations are key-local, so basic pushes/pops work naturally in Cluster. Multi-key blocking/move operations have additional same-slot/routing constraints; Chapter 21 treats those precisely.

7. Hands-on lab: AtlasMart bounded order feed

Build one store feed with a deliberate 20-item retention target. Use only atlasmart:ch05:* keys.

redis-cli · feed setup and verification
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:store:42:ordersdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LPUSH atlasmart:ch05:store:42:orders order:2001 order:2002 order:2003docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LRANGE atlasmart:ch05:store:42:orders 0 -1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LTRIM atlasmart:ch05:store:42:orders 0 19docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LLEN atlasmart:ch05:store:42:ordersdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TYPE atlasmart:ch05:store:42:ordersdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch05:store:42:orders

Verification: state which item is head/tail; explain the multi-element LPUSH order; verify length ≤20; record memory as an environment-specific observation, not a universal byte-per-element constant.

8. Production judgment

Use a List when the important abstraction is a key-local ordered deque: recent history, a bounded stack, or a simple work queue whose loss/retry semantics you fully own. Define maximum length, payload size, consumer orientation, timeouts, and observability. Avoid unbounded ranges and unbounded growth. If a worker needs acknowledgment, replay, pending-message inspection, or recovery by another consumer, a Stream usually expresses those requirements more directly.

9. Summary and next step

Lists preserve sequence and offer O(1)-style end operations for common push/pop cases, but they do not automatically provide delivery acknowledgments or replay. Next, blocking operations make a list behave like a waiting work queue—and expose exactly where “simple queue” reliability stops.

Check your understanding

  1. With RPUSH producers and LPOP consumers, which item is processed first?
  2. Why can LPUSH key a b c appear reversed when read left-to-right?
  3. Why is LRANGE 0 -1 dangerous as a default production API?
  4. What does LTRIM 0 99 guarantee and what does it destroy?
  5. Why does AOF persistence not make a list-backed worker exactly-once?
Review the answers

FIFO: the oldest element at the head is popped first.

Each argument is prepended to the head; the last argument becomes the first visible element.

It returns the entire list, so server work, reply bytes, network time, and client memory grow with the result.

It retains the first 100 indexed elements and removes the rest from that list; it is retention, not archival.

Persistence concerns Redis state recovery. It does not add application processing acknowledgment, idempotency, or crash recovery between pop and side effect.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.