Choose Lists, Sets, Streams, or Sorted Sets from ordering, membership, replay, acknowledgment, and score semantics—not command convenience.

Choose List vs Set vs Stream vs Sorted Set from Ordering, Delivery, Replay, and Membership Needs

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

Intermediate145–180 minutesCross-structure decision + migration labRedis Open Source 8.10.1Free/local-firstLast reviewed: September 6, 2026

Learning outcomes

AtlasMart has four superficially similar needs: a recent ordered activity feed, a unique VIP audience, durable fulfillment work with retries, and delayed jobs scheduled by time. Choosing a structure because one command looks convenient creates hidden reliability and cost problems. Choose from semantics first.

01

Choose a List when ordered deque behavior is primary and replay/ack state is not.

02

Choose a Set when exact unique membership is primary and order is irrelevant.

03

Choose a Stream when retained entries, IDs, consumer groups, pending state, acknowledgment, and replay matter.

04

Choose a Sorted Set when score-ordered ranking/scheduling/range queries matter.

05

Document migration, retention, persistence, Cluster, retry, and observability consequences of the choice.

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. Start with the invariant, not the command

Question List Set Stream Sorted Set
Primary order Sequence by list position None Entry ID order Score then member ordering
Uniqueness No Yes, exact member uniqueness No inherent member uniqueness Unique member with mutable score
Blocking wait Yes No Yes for reads No direct queue-block primitive
Replay/history Only retained list elements Membership only Yes, retained entries/IDs Range by score/rank while retained
Consumer acknowledgment No built-in Not applicable Consumer groups + XACK Application-built
Pending/reclaim Application-built Not applicable PEL + claim mechanisms Application-built
Best-fit examples bounded feed/simple queue tags/audiences/dedupe events/work processing leaderboard/delayed schedule

2. Same business story, four different models

Model one AtlasMart fulfillment event in four structures and inspect what each one remembers.

redis-cli · four structures, four semantics
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:model:list atlasmart:ch05:model:set atlasmart:ch05:model:stream atlasmart:ch05:model:zsetdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app RPUSH atlasmart:ch05:model:list order:8001docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SADD atlasmart:ch05:model:set customer:vip:88docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app XADD atlasmart:ch05:model:stream "*" order order:8001 state queueddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch05:model:zset 1893456000 order:8001docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TYPE atlasmart:ch05:model:listdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TYPE atlasmart:ch05:model:setdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TYPE atlasmart:ch05:model:streamdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TYPE atlasmart:ch05:model:zset

The commands all “store something,” but the data structures preserve different facts: sequence, membership, event history, or score order. Migration between them is a semantic migration, not merely a syntax change.

3. Ordering: position, ID, and score are different

A List's order is explicit element position changed by pushes/pops. A Stream entry has an ID and remains addressable while retained; consumer groups add delivery state. A Sorted Set orders unique members by numeric score and then member tie-breaking rules. A Set has no business ordering contract. If the requirement says “oldest queued item,” “event history,” “highest rank,” or “is member?”, those are four different questions.

4. Delivery and replay decide queue architecture

If work may be lost/retried and you need to know which consumer owns unfinished work, a Stream consumer group is usually a better primitive than a destructive List pop. A List can be upgraded with processing lists, but you then own acknowledgment/reclaim metadata. Neither primitive makes external side effects exactly-once. A durable broker outside Redis may be warranted for requirements beyond Redis's intended topology/retention/ecosystem envelope.

5. Membership and algebra decide audience architecture

Sets excel when the dominant operations are add/remove member, membership test, cardinality, and set algebra. A Sorted Set also has unique members but adds a score and ranking/range semantics at extra conceptual and memory cost. Do not choose a Sorted Set merely because “we may sort someday”; choose it when score order is already part of the contract.

6. Scheduling and ranking decide Sorted Set architecture

For delayed work, store the due timestamp as score and the job ID as member. The scheduler asks for due ranges. This is not the same as a List queue: producers can insert future jobs out of arrival order, and consumers must define claiming/removal/retry semantics.

redis-cli · minimal delayed-work model
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:scheduledocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch05:schedule 100 job:early 300 job:late 200 job:middledocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZRANGE atlasmart:ch05:schedule 0 -1 WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZRANGEBYSCORE atlasmart:ch05:schedule -inf 200 WITHSCORES

Chapter 06 develops Sorted Sets fully. Here the point is selection: score order is native there and absent from Lists/Sets.

7. Persistence, replication, and Cluster are orthogonal dimensions

Data-structure choice does not select durability automatically. RDB/AOF, asynchronous replication, Sentinel, and Cluster each add different recovery/availability semantics. In Cluster, multi-key List/Set operations may require same-slot locality; Streams and Sorted Sets can also become hot keys. Plan key distribution, payload/cardinality, failover ambiguity, and client retries separately from the abstract data model.

8. Deliberately wrong: choose the shortest command

An engineer picks BLPOP because it is one line, then later adds retries, history, multiple consumer groups, pending recovery, and auditing. The system gradually rebuilds Stream semantics around Lists. Another engineer uses a Set for “next worker” and discovers there is no ordering/fairness contract.

Repair: write a one-page decision record before implementation. State ordering, uniqueness, retention, replay, acknowledgment, recovery, membership, score/range queries, expected cardinality, payload size, concurrency, persistence, topology, and migration path.

text · decision record skeleton
Structure: <List | Set | Stream | Sorted Set>Business invariant:Ordering contract:Uniqueness contract:Retention / replay:Acknowledgment / retry / reclaim:Expected cardinality and payload size:Hot-key / Cluster locality:Persistence and failover assumptions:Observability signals:Migration + rollback plan:

9. Hands-on decision lab

Use the same small fixture to answer four different questions.

redis-cli · compare observable questions
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app LRANGE atlasmart:ch05:model:list 0 -1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SISMEMBER atlasmart:ch05:model:set customer:vip:88docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app XRANGE atlasmart:ch05:model:stream - + COUNT 10docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZRANGE atlasmart:ch05:model:zset 0 -1 WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch05:model:listdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch05:model:setdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch05:model:streamdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch05:model:zset

Do not compare these four tiny MEMORY USAGE values as a universal “winner.” Real memory depends on element counts, sizes, encodings, IDs/metadata, scores, allocator behavior, and feature version. Benchmark representative datasets.

10. Migration and rollback

Changing structures can change ordering and failure semantics. A safe migration often dual-writes for a bounded period, validates counts/order/business outcomes, backfills historical state if required, cuts readers over behind a feature flag, and preserves a rollback window. Dual-write itself can fail partially, so reconciliation is mandatory. Never delete the old structure until the new path has proven correctness under retries, failover, and load.

10.1 Cleanup/reset the Chapter 05 decision fixtures

After the comparison, remove only the synthetic Chapter 05 keys. Cleanup is explicit so rerunning the lesson starts from known state without touching any unrelated Redis data.

redis-cli · chapter decision-lab cleanup
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:model:list atlasmart:ch05:model:set atlasmart:ch05:model:stream atlasmart:ch05:model:zsetdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:schedule

Do not use FLUSHDB or FLUSHALL for course cleanup; the shared lab may contain state from earlier chapters.

11. Production judgment

Prefer the simplest structure that natively represents the invariant you actually need. Simplicity means fewer application-built correctness mechanisms—not merely fewer command characters. Lists are ordered deques; Sets are unique membership; Streams are retained event/work logs with group delivery state; Sorted Sets are score-ordered unique members. Revisit the decision when cardinality, retention, multi-reader behavior, retry policy, or topology changes.

12. Summary and next step

Chapter 05 separated sequence, membership, delivery state, replay, and ranking so “Redis collection” no longer means one generic bucket. Chapter 06 now focuses on Sorted Sets: scores, ranks, ranges, leaderboards, scheduling, and aggregation.

Check your understanding

  1. Which structure natively answers “is customer 88 in the VIP audience?”
  2. Which structure natively tracks delivered-but-unacknowledged work for a consumer group?
  3. Which structure best represents due-time ordering by numeric timestamp?
  4. Why is a processing List not automatically equivalent to a Stream consumer group?
  5. What must a migration validate besides element counts?
Review the answers

A Set.

A Stream with a consumer group and its Pending Entries List.

A Sorted Set, using due time as score.

The application must build ownership, acknowledgment, reclaim, history, and retry metadata around Lists.

Ordering, uniqueness, replay/retention, retry/ack semantics, business side effects, topology behavior, performance, and rollback/reconciliation.

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.