Redis Data Structures
Redis supports strings, lists, sets, sorted sets, hashes, streams, bitmaps, and HyperLogLogs. Each structure solves different problems: sorted sets for leaderboards, streams for event logs.
What is Redis Data Structures?
In short
Redis data structures are the built-in value types Redis stores in memory and operates on with atomic commands: strings, lists, hashes, sets, sorted sets, streams, bitmaps, HyperLogLogs, and geospatial indexes. Instead of storing dumb blobs, Redis understands the shape of your data, so you can push to a list, increment a counter, or rank a leaderboard in a single fast command.
What they actually are
A Redis key always maps to one value, but that value is not just text. Redis gives the value a type, and each type has its own set of commands. A string holds bytes or a number you can increment. A list is an ordered sequence you push and pop from either end. A hash is a map of field names to values, like a small object. A set is an unordered collection of unique members. A sorted set is the same but every member carries a floating point score that keeps it ordered. A stream is an append-only log of entries with IDs. Bitmaps, HyperLogLogs, and geospatial indexes are specialized views layered on top of strings and sorted sets.
Because Redis knows the type, the work happens server side in C. You send LPUSH or ZADD or HINCRBY and Redis mutates the structure in place. You never read a whole object, change it in your app, and write it back. That round trip is what kills throughput in a plain key-value store, and Redis avoids it.
Every command on these structures is atomic. Redis runs commands one at a time on a single thread per shard, so an INCR or a ZADD either fully happens or does not happen. There is no torn read between two clients.
How they work under the hood
Redis picks the internal representation based on size to save memory. A small hash or sorted set is stored as a compact listpack, a flat array packed into a single allocation. Once it grows past a configured threshold, around 128 entries or 64 byte values by default, Redis converts it to a real hash table or skiplist. You get small footprint when data is tiny and good asymptotic behavior when it is large, without changing your code.
Sorted sets are the clever one. They keep both a hash table mapping member to score and a skiplist ordered by score. The hash table makes ZSCORE an O(1) lookup. The skiplist makes range queries like ZRANGEBYSCORE and rank lookups like ZRANK run in O(log n). That dual structure is why a leaderboard with millions of players still answers top-ten and my-rank queries instantly.
Lists use a quicklist, a linked list of listpack nodes, so pushing and popping at the ends is O(1) while memory stays compact. Streams use a radix tree of entry IDs, which is what lets consumer groups track per-consumer read positions and acknowledgments. The point is that each type maps to a data structure chosen for its access pattern, not a one-size-fits-all store.
When to use them and the trade-offs
Reach for the matching type instead of serializing JSON into a string. Use a hash for an object you update field by field, like a user session, so you can HSET one field without rewriting the whole thing. Use a sorted set for anything ranked or time-ordered: leaderboards, rate limiters keyed by timestamp, priority queues. Use a list for simple queues and recent-activity feeds. Use a set for membership and tags, and SINTER or SUNION for things like mutual followers. Use a stream when you need a durable event log with multiple consumers that each track their own position.
The hard limit is memory. Everything lives in RAM, so a 50 GB dataset needs roughly 50 GB plus overhead, which is far more expensive than disk. Persistence with RDB snapshots or the AOF log protects against restarts but does not change the working set size. Watch out for big collections too: a command like ZRANGE over a million-member set, or KEYS in production, can block the single thread and stall every other client.
HyperLogLog is the classic trade-off example. It estimates the number of unique items in about 12 KB regardless of cardinality, with roughly 0.81 percent error. You give up exact counts and the ability to list members, and in return you count billions of uniques in a fixed tiny space.
A concrete real-world example
A live game leaderboard is the textbook case. You store one sorted set per leaderboard. When a player scores, you call ZADD leaderboard 4820 player:1234, an O(log n) write. To show the top ten you call ZREVRANGE leaderboard 0 9 WITHSCORES. To show a player their own standing you call ZREVRANK leaderboard player:1234, which returns their position in O(log n) even among ten million players.
Compare that to a relational table. Getting a player's rank means ORDER BY score plus a COUNT of everyone above them, which scans or needs a maintained index and gets slow under write pressure. Redis keeps the ranking ordered continuously, so reads and writes both stay fast.
Layer other structures on the same feature. A hash holds each player's profile fields. A string with INCR counts total games played. A stream records every score event so an analytics consumer can replay them. One Redis instance, several types, each doing the job it is shaped for.
Where it is used in production
Twitter / X
Used Redis sorted sets and lists to assemble per-user home timelines, ranking and fanning out tweets in memory.
Discord
Stores recent message and presence state in Redis structures so channels render instantly without hitting the primary database every time.
GitHub
Uses Redis for job queues and rate limiting, leaning on lists and sorted sets keyed by time windows to throttle API traffic.
Stack Overflow
Caches rendered pages and counters in Redis strings and hashes, with INCR driving view counts at high request rates.
Frequently asked questions
- What is the difference between a Redis set and a sorted set?
- A set stores unique members with no order and is built for membership tests and set math like intersection and union. A sorted set stores unique members where each carries a numeric score that keeps them ordered, so you can query by rank or score range. Use a set for tags and uniqueness, a sorted set for leaderboards and anything ranked.
- When should I use a hash instead of just storing JSON in a string?
- Use a hash when you update individual fields. With a hash you can HSET or HINCRBY one field without reading and rewriting the whole object, and small hashes are stored compactly. Store JSON in a string only when you always read and write the whole value at once and never need to touch single fields server side.
- Are Redis data structure operations atomic?
- Yes. Each command runs to completion on a single thread per shard, so operations like INCR, LPUSH, and ZADD either fully happen or do not, with no torn state between clients. For multiple commands that must run together, use MULTI/EXEC transactions or a Lua script, which also execute atomically.
- How much memory does a Redis data structure use?
- Everything lives in RAM, so cost scales with data size plus overhead. Small collections use compact listpack encoding to save space, then convert to full hash tables or skiplists past a size threshold like 128 entries. HyperLogLog is the exception, estimating unique counts in about 12 KB no matter how many items you add.
- What is a Redis stream used for?
- A stream is an append-only log of entries, each with a time-ordered ID. It is meant for event sourcing and message passing where multiple consumers each track their own read position. Consumer groups let several workers split a stream and acknowledge processed entries, which makes streams a lightweight alternative to a dedicated message broker for many workloads.
Learn Redis Data Structures hands-on
This page explains the idea. The full lesson lets you step through the ring as servers join and leave, read the implementation, and check yourself with a quiz. It is one of 760+ lessons in the System Design Masterclass, from your first API call to distributed consensus. Eleven Foundation lessons are free, no signup. Lifetime access is ₹499 in India or $7.99 worldwide, one payment, no subscription.
See also
Related glossary terms you might want to look up next.
Redis
An in-memory data store used as a cache, message broker, and database. Blazing fast because everything lives in RAM.
Caching
Storing frequently accessed data in a faster storage layer so you don't have to fetch it from the original (slower) source every time.
Key-Value Store
The simplest NoSQL model: store data as key-value pairs. Blazing fast lookups by key. Redis, DynamoDB, and etcd are key-value stores.
Memcached
A simple, high-performance distributed memory caching system. Stores key-value pairs in RAM. Simpler than Redis but less feature-rich.
Document Database
A NoSQL database that stores data as flexible JSON-like documents. MongoDB and CouchDB let each document have a different structure.
Column-Family Store
A NoSQL database that groups columns into families, optimized for reading and writing large amounts of data across many machines. Cassandra and HBase use this model.