Build real-time rankings with Sorted Sets: O(log N) score updates, O(log N) rank lookups, and efficient range queries for top-N or around-me leaderboards.
Sorted Sets provide automatic ordering by score, making them ideal for gaming leaderboards, trending content, and any ranking of potentially millions of items with instant updates.
A Sorted Set stores members with associated scores, automatically maintaining order by score.
Add or update a player's score:
ZADD leaderboard 1500 "player:alice"
ZADD leaderboard 2300 "player:bob"
ZADD leaderboard 1800 "player:charlie"
Get the top 10 players (highest scores first):
ZRANGE leaderboard 0 9 REV WITHSCORES
Get a player's rank (0-indexed, where 0 is the highest):
ZRANK leaderboard "player:alice" REV
Note: Redis 6.2+ unified range commands.
ZRANGEwithREVreplacesZREVRANGE. The old commands still work but the unified syntax is preferred.
Get a player's score:
ZSCORE leaderboard "player:alice"
Increment a player's score:
ZINCRBY leaderboard 50 "player:alice"
Redis provides two ranking commands:
- ZRANK returns position sorted low-to-high (lowest score = rank 0)
- ZREVRANK returns position sorted high-to-low (highest score = rank 0)
For most games, ZREVRANK is appropriate since higher scores are better.
To show a player their position relative to nearby competitors:
ZREVRANGE leaderboard 45 55 WITHSCORES
This retrieves players ranked 46th through 56th (ranks 45-55 in 0-indexed terms).
When two players have identical scores, you may want the player who achieved it first to rank higher. Since Sorted Sets don't natively support secondary sort keys, encode both values into a single score.
For a score of 1500 achieved at timestamp 1706648400:
composite_score = score * 10000000000 + (MAX_TIMESTAMP - timestamp)
This ensures: - Higher scores always rank first (score dominates) - For equal scores, earlier timestamps rank higher (because we subtract from MAX_TIMESTAMP)
The original score can be recovered by integer division: original_score = composite_score // 10000000000
For "Top players this week" or "Daily high scores," create separate Sorted Sets with time-based key names:
ZADD leaderboard:daily:2024-01-30 1500 "player:alice"
ZADD leaderboard:weekly:2024-W05 1500 "player:alice"
Set appropriate TTLs for automatic cleanup:
EXPIRE leaderboard:daily:2024-01-30 172800
This keeps daily leaderboards for 2 days after the day ends.
Combine multiple leaderboards using ZUNIONSTORE:
ZUNIONSTORE leaderboard:week leaderboard:day:mon leaderboard:day:tue ... AGGREGATE MAX
The AGGREGATE option controls how scores combine:
- SUM: Add scores (total points across days)
- MAX: Take highest score (personal best)
- MIN: Take lowest score (best time in racing)
For large leaderboards, paginate results:
Page 1 (items 1-20):
ZREVRANGE leaderboard 0 19 WITHSCORES
Page 2 (items 21-40):
ZREVRANGE leaderboard 20 39 WITHSCORES
Use ZCARD to determine total pages:
ZCARD leaderboard
To get a player's rank and score in one round-trip, use pipelining:
ZREVRANK leaderboard "player:alice"
ZSCORE leaderboard "player:alice"
Both commands execute in a single network round-trip when pipelined, returning rank and score together.
| Command | Description | Complexity |
|---|---|---|
| ZADD | Add/update score | O(log N) |
| ZINCRBY | Increment score | O(log N) |
| ZRANK key member REV | Get rank (high to low) | O(log N) |
| ZRANK | Get rank (low to high) | O(log N) |
| ZSCORE | Get score | O(1) |
| ZRANGE key start stop REV | Get range by rank (high to low) | O(log N + M) |
| ZCARD | Get total count | O(1) |
| ZUNIONSTORE | Merge leaderboards | O(NK + Mlog M) |
Unified ZRANGE: The ZRANGE command now supports REV, BYSCORE, BYLEX, and LIMIT options, replacing ZREVRANGE, ZRANGEBYSCORE, and ZRANGEBYLEX with a single command.
ZRANGESTORE: Store range results in a new key instead of returning them:
ZRANGESTORE top10:cache leaderboard 0 9 REV
This creates a snapshot of the top 10 that can be read without re-querying the main leaderboard.
ZMPOP (Redis 7.0+): Pop minimum or maximum elements from multiple sorted sets:
ZMPOP 1 leaderboard MAX COUNT 3
Removes and returns the top 3 players—useful for tournament elimination or reward distribution.
GETEX pattern: For leaderboards with TTL, consider using a Hash alongside the Sorted Set to store player metadata, using GETEX to refresh TTL on access.