Mastering Redis Data Types: When to Use Strings, Lists, Hashes, Sets, Zsets and More

This comprehensive guide explains Redis's core data types—including String, List, Hash, Set, Zset, BitMap, HyperLogLog, GEO and Stream—detailing their internal implementations, common commands, and real‑world application scenarios such as caching, counting, messaging queues, ranking, geolocation and unique‑ID generation.

ITPUB
ITPUB
ITPUB
Mastering Redis Data Types: When to Use Strings, Lists, Hashes, Sets, Zsets and More

Redis Data Types Overview

Redis provides nine data types: five classic types (String, Hash, List, Set, Sorted Set) and four newer types (Bitmap, HyperLogLog, GEO, Stream). Each type has a specific internal representation and is suited to particular workloads.

String

Introduction

String is the simplest key‑value structure. Values can be text, binary data, or numbers and may be up to 512M in size.

Internal Implementation

String objects are encoded as int, embstr, or raw. Small integers use the int encoding. Short strings (≤32 bytes) use embstr, which allocates a single contiguous memory block for the redisObject and its SDS buffer. Longer strings use raw, allocating the object and SDS separately. All encodings store the value in an SDS (Simple Dynamic String), which provides O(1) length lookup and safe concatenation.

Common Commands

# Set a key‑value pair
SET name lin
# Get the value
GET name
# Check existence
EXISTS name
# Get length of the string
STRLEN name
# Delete a key
DEL name
# Increment / decrement numeric strings
INCR name
DECR name
# Set with expiration
SET key value EX 60
# Set only if not exists (useful for locks)
SETNX lock_key unique_value

Application Scenarios

Object caching : cache a whole JSON object ( SET user:1 '{"name":"xiaolin","age":18}') or store fields separately with MSET / MGET.

Counters : atomic increments for page views, likes, inventory, etc. Example:

# Initialize counter
SET article:readcount:1001 0
# Increment
INCR article:readcount:1001
# Get current count
GET article:readcount:1001

Distributed lock : acquire with SET lock_key unique_value NX PX 10000 (10 s TTL). Release atomically using Lua:

if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

List

Introduction

List is an ordered collection of strings. Elements can be pushed or popped from both head and tail. Maximum length is 2^32‑1 (over 4 billion elements).

Internal Implementation

Since Redis 3.2, Lists are implemented with a quicklist, a linked list of ziplist nodes. This replaces the older separate doubly linked list and ziplist implementations.

Common Commands

# Push to head
LPUSH key value [value ...]
# Push to tail
RPUSH key value [value ...]
# Pop from head
LPOP key
# Pop from tail
RPOP key
# Get a range of elements
LRANGE key start stop
# Blocking pop from head
BLPOP key [key ...] timeout
# Blocking pop from tail
BRPOP key [key ...] timeout

Application Scenarios

Message queue (FIFO) : use LPUSH + RPOP for simple queues. For consumers that should wait for new messages, use BRPOP to block without busy‑waiting.

Reliable consumption : BRPOPLPUSH source dest timeout copies a message to a backup list before removing it from the source, allowing replay on consumer failure.

Limitations : Lists do not support consumer groups; high producer‑consumer speed imbalance can cause memory pressure.

Hash

Introduction

Hash stores a mapping of fields to values under a single key, ideal for representing objects (e.g., user profiles).

Internal Implementation

Hashes use a ziplist (now replaced by listpack in Redis 7.0) when the number of fields < 512 and each field/value < 64 bytes. Otherwise a hash table is used.

Common Commands

# Set a field
HSET key field value
# Get a field
HGET key field
# Set multiple fields
HMSET key field value [field value ...]
# Get multiple fields
HMGET key field [field ...]
# Delete fields
HDEL key field [field ...]
# Number of fields
HLEN key
# Get all fields and values
HGETALL key
# Increment numeric field
HINCRBY key field increment

Application Scenarios

Object caching : store user attributes as separate fields. Example:

HSET uid:1 name Tom age 15
HGETALL uid:1

Shopping cart : key = user ID, field = product ID, value = quantity.

# Add product
HSET cart:123 456 1
# Increment quantity
HINCRBY cart:123 456 1
# Remove product
HDEL cart:123 456
# Retrieve cart
HGETALL cart:123

Set

Introduction

Set is an unordered collection of unique elements. It can store up to 2^32‑1 members.

Internal Implementation

Sets are backed by a hash table. When all members are integers and the set size < 512, an integer set ( intset) is used for compact storage.

Common Commands

# Add members
SADD key member [member ...]
# Remove members
SREM key member [member ...]
# Get all members
SMEMBERS key
# Cardinality
SCARD key
# Membership test
SISMEMBER key member
# Random member(s)
SRANDMEMBER key [count]
# Pop random member(s)
SPOP key [count]
# Set operations
SINTER key [key ...]
SINTERSTORE destkey key [key ...]
SUNION key [key ...]
SUNIONSTORE destkey key [key ...]
SDIFF key [key ...]
SDIFFSTORE destkey key [key ...]

Application Scenarios

Deduplication / uniqueness : e.g., store user IDs that liked an article. SADD article:1 uid:1 then SCARD article:1 gives like count.

Set algebra : compute intersections for mutual interests, unions for combined audiences, and differences for exclusive sets.

Lottery : store participants in a Set; draw winners with SPOP (no repeats) or SRANDMEMBER (allow repeats).

Sorted Set (Zset)

Introduction

Zset adds a floating‑point score to each member, enabling ordered retrieval while preserving member uniqueness.

Internal Implementation

Small Zsets (<128 members, each < 64 bytes) use a ziplist (replaced by listpack in Redis 7.0); larger sets use a skiplist.

Common Commands

# Add members with scores
ZADD key score member [score member ...]
# Remove members
ZREM key member [member ...]
# Get a member's score
ZSCORE key member
# Cardinality
ZCARD key
# Increment score
ZINCRBY key increment member
# Range query (ascending)
ZRANGE key start stop [WITHSCORES]
# Range query (descending)
ZREVRANGE key start stop [WITHSCORES]
# Score range query
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
# Lexicographic range (same score)
ZRANGEBYLEX key min max [LIMIT offset count]
# Union / intersect
ZUNIONSTORE destkey numkeys key [key ...] [WEIGHTS w1 w2 ...] [AGGREGATE SUM|MIN|MAX]
ZINTERSTORE destkey numkeys key [key ...] [WEIGHTS w1 w2 ...] [AGGREGATE SUM|MIN|MAX]

Application Scenarios

Leaderboards / ranking : store scores (e.g., article likes) and retrieve top N with ZREVRANGE.

# Add articles with like counts
ZADD ranking 200 article:1
ZADD ranking 40  article:2
ZADD ranking 100 article:3
ZADD ranking 50  article:4
ZADD ranking 150 article:5
# Increment a like
ZINCRBY ranking 1 article:4
# Top 3 articles
ZREVRANGE ranking 0 2 WITHSCORES

Lexicographic sorting : when all scores are equal, use ZRANGEBYLEX to sort strings such as phone numbers or names.

# Store phone numbers with score 0
ZADD phone 0 13100111100 0 13110114300 0 13132110901
# Get all numbers
ZRANGEBYLEX phone - +
# Get numbers with prefix 132
ZRANGEBYLEX phone [132 (133

Bitmap

Introduction

Bitmap is a compact binary array (bits) built on top of the String type. Each bit represents a boolean state (0/1) and operations are O(1).

Internal Implementation

Bitmap uses a String as the underlying storage; each byte of the string is treated as eight bits.

Common Commands

# Set a bit (value must be 0 or 1)
SETBIT key offset value
# Get a bit
GETBIT key offset
# Count bits set to 1 in a byte range
BITCOUNT key start end
# Bitwise operations across multiple bitmaps
BITOP AND destkey key1 [key2 ...]
BITOP OR  destkey key1 [key2 ...]
BITOP XOR destkey key1 [key2 ...]
BITOP NOT destkey key1
# Find first occurrence of a bit value
BITPOS key value

Application Scenarios

Sign‑in tracking : each day of a month is a bit. Example for user 100 on June 3 (offset 2):

SETBIT uid:sign:100:202206 2 1   # mark sign‑in
GETBIT uid:sign:100:202206 2       # check
BITCOUNT uid:sign:100:202206       # total sign‑ins
BITPOS uid:sign:100:202206 1      # first sign‑in day (offset +1)

User online status : store a bit per user ID in a single key.

# User logs in
SETBIT login_status 10086 1
# Check status
GETBIT login_status 10086
# User logs out
SETBIT login_status 10086 0

Consecutive sign‑in count : AND multiple daily bitmaps to find users who signed in every day.

# AND three daily bitmaps
BITOP AND daily_all bitmap:01 bitmap:02 bitmap:03
# Count users present all three days
BITCOUNT daily_all

HyperLogLog

Introduction

HyperLogLog provides an approximate distinct count with a standard error of 0.81 % using only 12 KB per key, regardless of the number of elements.

Common Commands

# Add elements
PFADD key element [element ...]
# Get estimated cardinality
PFCOUNT key [key ...]
# Merge multiple HyperLogLogs
PFMERGE destkey sourcekey [sourcekey ...]

Application Scenarios

UV (unique visitor) counting : add each visitor identifier to a HyperLogLog and retrieve the estimate with PFCOUNT. Suitable for high‑traffic pages where exact counts are unnecessary.

GEO

Introduction

GEO stores longitude/latitude pairs using the Sorted Set data structure and GeoHash encoding, enabling fast radius queries for location‑based services.

Common Commands

# Add a location
GEOADD cars:locations longitude latitude member
# Get position of a member
GEOPOS cars:locations member
# Compute distance between two members
GEODIST cars:locations member1 member2 km
# Find members within a radius
GEORADIUS cars:locations longitude latitude radius km ASC COUNT 10

Application Scenario

Ride‑hailing services store vehicle coordinates with GEOADD and locate nearby cars with GEORADIUS.

Stream

Introduction

Stream, introduced in Redis 5.0, is a log‑structured data type designed for reliable message queues. It automatically generates a globally unique ID for each entry and supports consumer groups.

Common Commands

# Append a message (auto‑generated ID)
XADD mymq * name xiaolin
# Read from a specific ID (non‑blocking)
XREAD STREAMS mymq 1654254953807-0
# Blocking read (wait up to 10 s)
XREAD BLOCK 10000 STREAMS mymq $
# Create a consumer group
XGROUP CREATE mymq group1 0
# Read as part of a group (only unclaimed messages)
XREADGROUP GROUP group1 consumer1 STREAMS mymq >
# Acknowledge processing
XACK mymq group1 1654254953808-0
# View pending (unacknowledged) messages
XPENDING mymq group1

Application Scenario

Message queue with ordering and reliability : producers use XADD to push events; consumers belong to a group and use XREADGROUP to claim messages. Unacknowledged messages remain in the internal pending list and can be inspected with XPENDING and later acknowledged with XACK, ensuring that a consumer crash does not lose work.

Consumer groups : multiple consumers can share the load; each message is delivered to only one consumer in the group.

Blocking consumption : XREAD BLOCK provides a wait‑until‑message behavior similar to BRPOP for Lists.

Note: Redis streams store data in memory, so setting a maximum length (e.g., XADD ... MAXLEN ~ 10000) is recommended to avoid uncontrolled memory growth.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

CacheredisMessage QueueData Types
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.