jongkwan.dev
Development · Essay №057

Redis Data Structures and How to Use Them

The five core Redis types and the specialized ones, organized by internal encoding, operation complexity, and practical use

Jongkwan Lee2026년 3월 4일8 min read
Contents

Redis offers different ways to store a value, split by type. Picking the type that matches the problem shrinks both the code and the memory footprint.

An identity as a data structure server

Redis is an in-memory data store that keeps everything in memory. Latency is lower than a disk-based database, and every command executes atomically. The official documentation defines Redis as a data structure server.

That definition is what separates it from an ordinary key-value cache. Instead of reading and writing whole values, the server itself performs operations such as appending an element to a list or intersecting two sets. That removes round trips where the application downloads a large value, transforms it, and writes it back.

Read and write throughput is high as well. The official Redis benchmark uses 50 clients, a 256-byte payload, and Redis Open Source 8.x. Under those conditions, String GET and SET handle roughly 170,000 to 220,000 operations per second. The single-threaded design means no contention between commands.

The five core types

String, Hash, List, Set, and Sorted Set are the types used most often. Each one is good at a specific set of operations.

TypeStructureStrong operationsTypical use
Stringsingle valueGET/SET, INCRcached values, counters
Hashfield-value mapHSET/HGETobject profiles
Listordered dequeLPUSH/BRPOPjob queues, timelines
Setset without duplicatesSADD, SINTERtags, deduplication
Sorted Setset ordered by scoreZADD, ZRANGEreal-time leaderboards

The "strong operations" column is the criterion for choosing a type. Even for the same data, the type follows from which queries are frequent.

String is the most basic type and can hold up to 512MB. Integer values support atomic increment, which makes it a good fit for counters.

text
SET page:home "<html>"          -> OK
INCR pv:home                    -> 1 (starts from 0 when absent)
SETEX session:abc 60 "uid42"    -> stored with a 60-second TTL

SETEX on the last line stores a value together with an expiry. TTL stands for Time To Live, the lifetime after which the key is deleted automatically.

Hash groups multiple fields of an object under one key. It saves memory compared to giving each field its own String key.

text
HSET user:1001 name "Alice" age 25
HGET user:1001 name             -> "Alice"
HINCRBY user:1001 age 1         -> 26
HGETALL user:1001               -> all field-value pairs

Storing the same data as a Hash instead of individual Strings can cut memory substantially (roughly 50% to 90% depending on the data, estimated). The more small objects involved, the larger the difference.

List is an ordered collection with O(1) push and pop at both ends. Set is a collection without duplicates where membership checks are O(1).

text
LPUSH jobs "task1"              push a job to the front of the queue
BRPOP jobs 5                    pop from the back, wait up to 5 seconds if empty
SADD tags:post1 "redis" "db"    add tags without duplicates
SINTER tags:post1 tags:post2    tags shared by two posts (intersection)

BRPOP is a blocking command that waits the given number of seconds when no element is available. That single line builds a job queue without any polling.

Sorted Set assigns a score to each member and keeps them ordered automatically. It suits leaderboards, where sorting and rank lookups are frequent.

text
ZADD rank 100 "Alice" 120 "Bob"
ZREVRANGE rank 0 2 WITHSCORES   top 3 with their scores
ZRANK rank "Bob"                ascending rank of "Bob"
ZINCRBY rank 5 "Alice"          increase "Alice" score by 5

Changing a score updates the internal position immediately, so updates and rank lookups need no separate index.

Internal encoding and memory

Redis changes the internal representation of a type depending on size. Small collections go into a compact memory block, and larger ones switch to a hash table or a skip list.

Data typeRedis 6.2 and earlierRedis 7.0 and later
Stringraw / intraw / int
Hash (small)ziplistlistpack
List (small)ziplistlistpack
List (general)quicklistquicklist
Set (integers only)intsetintset
Sorted Setskiplistskiplist

Small Hashes and Lists live in a listpack (formerly called ziplist), a single contiguous block of memory. With no pointer overhead, it saves memory. A Set containing only integers uses intset, a sorted integer array, which is more compact still.

Check the actual encoding with the OBJECT ENCODING command.

text
OBJECT ENCODING user:1001       -> "listpack" or "hashtable"
OBJECT ENCODING rank            -> "skiplist"

The conversion thresholds are configurable. A redis.conf example looks like this.

conf
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size 8192

A Hash switches to hashtable once it exceeds 512 fields or holds a value longer than 64 bytes. Staying on listpack keeps memory small, but operations slow down on large collections, so set the thresholds to match object size.

Probabilistic and specialized types

Beyond the five core types there are types built for specific problems. They come into play when a little accuracy can be traded away, or when the domain involves something like coordinates.

Stream is an append-only log structure. Consumer groups and acknowledgements (ACK) let several workers split the message load.

text
XADD events * type "login" uid "42"     auto-generate the ID
XGROUP CREATE events g1 0               create a consumer group
XREADGROUP GROUP g1 c1 STREAMS events > read only new messages

Bitmap is an optimized string that represents one user's state in a single bit. For on/off counting such as daily login tracking, it uses very little memory.

text
SETBIT login:2026-06-30 42 1    mark that user 42 logged in today
BITCOUNT login:2026-06-30       number of users who logged in today

HyperLogLog is a probabilistic structure that estimates cardinality. It records only the hash distribution rather than storing every element.

text
PFADD uv:home "u1" "u2" "u3"
PFCOUNT uv:home                 estimated number of unique visitors

Per the official Redis documentation, one HyperLogLog uses a fixed 12KB and has a standard error of about 0.81%. Memory does not grow even when counting hundreds of millions of items, which fits Unique Visitor (UV) counting where an exact number is not required.

Geospatial places coordinates on top of a Sorted Set and provides distance and radius search.

text
GEOADD stores 126.97 37.56 "Store A"
GEOSEARCH stores FROMLONLAT 126.98 37.55 BYRADIUS 5 km ASC

GEOSEARCH returns members within the radius of a reference coordinate, nearest first. Internally it is a Sorted Set whose score encodes the coordinate, so location search works with no additional index.

How to choose a type

Even for the same data, the type follows from which queries you issue most often. The flow below maps query shape to type.

Including the specialized types, the problem-to-type mapping is as follows.

ProblemTypeKey commands
Real-time leaderboardSorted SetZADD / ZREVRANGE
Job queueListLPUSH / BRPOP
Unique visitor estimationHyperLogLogPFADD / PFCOUNT
Daily activity trackingBitmapSETBIT / BITCOUNT
Location-based searchGeospatialGEOADD / GEOSEARCH
Event streamStreamXADD / XREADGROUP

If ordering is central, Sorted Set fits; if an exact count is unnecessary and memory matters, HyperLogLog does. The deciding factor is the shape of the frequent queries, not the storage volume.

Summary

Redis is a data structure server, and each type differs in the operations it is good at and in its internal encoding. The five core types cover most caching and queueing needs. Problems such as ranking, unique counting, and location search hand off to specialized types like Sorted Set, HyperLogLog, and Geospatial. Internal encoding switches automatically with size, so grouping small objects into a Hash keeps them on listpack encoding and saves memory. Checking the actual representation with OBJECT ENCODING before shipping a new feature prevents production surprises.