What Redis Sorted Sets Are
A Redis sorted set (ZSET) is like a regular set — every member is unique — except each member also carries a floating-point score, and the structure is kept continuously ordered by that score using an internal skip list plus a hash table for O(1) score lookups by member. This dual structure gives you O(log n) insertion, removal, and rank queries via ZADD, ZREM, and ZRANK, which is exactly the profile needed for real-time leaderboards, priority queues, and time-ordered indexes.
Cricket analogy: A sorted set is like the live IPL Orange Cap leaderboard — every batter is a unique member, their run total is the score, and the list stays continuously ranked so Virat Kohli's position updates instantly the moment he scores another boundary.
Adding Members and Querying by Rank or Score
ZADD sets or updates a member's score (and supports GT/LT flags to only update if the new score is greater or less than the current one, and INCR to add to the existing score atomically like a ZSET version of INCR), while ZSCORE reads a single member's score. ZRANGE (with the BYSCORE or REV options in modern Redis) and the legacy ZRANGEBYSCORE let you fetch members within a score range or by rank position, and ZRANK/ZREVRANK tell you a specific member's zero-based position from the lowest or highest score.
Cricket analogy: ZADD with GT is like only updating a bowler's 'best figures' score if their new spell beats the current record, the way Jasprit Bumrah's tracked best-figures entry only changes when he actually improves on it.
# Leaderboard: add or update player scores
ZADD leaderboard 1500 "player:alice"
ZADD leaderboard 2200 "player:bob"
ZINCRBY leaderboard 50 "player:alice" # atomically add to existing score
# Only update if strictly better (e.g. a personal-best tracker)
ZADD pb:100m GT 9.58 "runner:usain"
# Top 3 by score, highest first, with scores
ZREVRANGE leaderboard 0 2 WITHSCORES
# Everyone scoring between 1000 and 2000
ZRANGEBYSCORE leaderboard 1000 2000
# A specific player's rank (0-based, highest score = rank 0)
ZREVRANK leaderboard "player:bob"
# Expire old entries from a time-ordered index (score = unix timestamp)
ZREMRANGEBYSCORE events:log 0 1751500000Leaderboards, Priority Queues, and Time-Ordered Indexes
The classic sorted-set use case is a leaderboard: ZADD to record or update a score, ZREVRANGE with WITHSCORES to display the top N players, and ZREVRANK to show any individual player their current rank — all served directly from Redis without a database sort. A second common pattern uses a Unix timestamp as the score to build a time-ordered index or a delayed-job priority queue, where ZRANGEBYSCORE with an upper bound of 'now' finds all jobs due to run, and ZADD with NX prevents accidentally rescheduling a job that's already queued.
Cricket analogy: Using a sorted set for the IPL Orange Cap race is like ZADD updating a batter's season run total after every innings and ZREVRANGE instantly serving the live top-10 to the broadcast graphics team.
ZADD GT and ZADD LT (added in Redis 6.2) let you implement 'record a new personal best' logic in a single atomic command — update the score only if the new value is strictly greater (or lesser) than the current one — without a client-side read-compare-write sequence.
Sorted set scores are IEEE 754 double-precision floats, so they lose exact integer precision above roughly 2^53. If you need exact ordering for very large integer IDs (like 19-digit snowflake IDs) as tie-breakers, encode them carefully — for example, combine a coarse timestamp score with the ID embedded in the member string itself rather than relying purely on score precision.
- A sorted set combines unique membership (like a Set) with a floating-point score that keeps members continuously ranked.
- ZADD, ZREM, and ZRANK/ZREVRANK run in O(log n) thanks to an internal skip list plus hash table.
- ZADD's GT/LT flags and ZINCRBY enable atomic 'update only if better' and 'add to score' patterns.
- ZRANGEBYSCORE and ZRANGE...BYSCORE fetch members within a score window, ideal for time-ordered or ranked queries.
- Leaderboards are the flagship use case: ZREVRANGE WITHSCORES for top-N, ZREVRANK for an individual's rank.
- Using a Unix timestamp as the score turns a sorted set into a delayed-job queue or time-ordered index.
- Scores are double-precision floats, so extremely large integer IDs can lose precision if relied on for exact ordering.
Practice what you learned
1. What distinguishes a Redis sorted set from a regular set?
2. What data structure does Redis use internally to keep a sorted set ordered efficiently?
3. Which command atomically adds to a member's existing score rather than replacing it?
4. What does ZADD with the GT flag do?
5. Why is a Unix timestamp commonly used as the score in a sorted set for a job queue?
Was this page helpful?
You May Also Like
Sets in Redis
Explore Redis Sets as unordered collections of unique strings, covering membership checks, set algebra like intersection and union, and randomized sampling.
Hashes in Redis
Learn how Redis Hashes model field-value objects efficiently, covering HSET/HGET, partial updates, memory-efficient small-hash encoding, and common object-modeling patterns.
Redis Streams
How Redis Streams model an append-only log, and how XADD, consumer groups, and trimming work together for durable event processing.