Sets

intermediate redis sets data-structures

A Redis set is an unordered collection of unique strings. Think of it like a Set<String> in Java or a Python set — adds are idempotent, duplicates are silently ignored, and membership checks are O(1).

What makes Redis sets special isn’t just storage — it’s the set algebra: intersection, union, difference, all running server-side in C.

The basics

SADD tags:post:99 "redis" "nosql" "cache"
# (integer) 3   — three new members

SADD tags:post:99 "redis"   # already there
# (integer) 0

SMEMBERS tags:post:99
# 1) "redis"
# 2) "nosql"
# 3) "cache"

SISMEMBER tags:post:99 "redis"
# (integer) 1
SISMEMBER tags:post:99 "graphql"
# (integer) 0

SCARD tags:post:99           # cardinality (size)
# (integer) 3

SREM tags:post:99 "cache"

The set algebra — where sets shine

This is the part most people don’t realize Redis can do. Suppose we have two sets of user IDs:

SADD users:premium 1 2 3 4 5 6
SADD users:active 4 5 6 7 8 9

SINTER users:premium users:active
# 1) "4"
# 2) "5"
# 3) "6"
# Premium AND active

SUNION users:premium users:active
# 1) "1" 2) "2" ... "9"
# Premium OR active

SDIFF users:premium users:active
# 1) "1" 2) "2" 3) "3"
# Premium but NOT active
Set Algebra
premium
{1,2,3,4,5,6}
SINTER
{4,5,6}
overlap
active
{4,5,6,7,8,9}

Classic use cases

Tags

SADD post:42:tags "redis" "interview" "backend"
SADD tag:redis:posts 42 87 99 101
SINTER tag:redis:posts tag:interview:posts     # posts tagged BOTH

Friends-in-common

SADD friends:alice 17 23 88 92
SADD friends:bob   23 55 88 101
SINTER friends:alice friends:bob
# 1) "23"
# 2) "88"

Unique visitors (small scale)

SADD visitors:2026-05-26 "user:42"
SADD visitors:2026-05-26 "user:43"
SCARD visitors:2026-05-26                       # unique count

For huge cardinalities (millions of unique values), switch to HyperLogLog — SADD storage grows linearly, HLL stays under 12 KB.

Random sampling

SRANDMEMBER tags:post:99 2     # 2 random members, no removal
SPOP queue:names               # 1 random member, removed

Useful for A/B testing, random featured items, lottery picks.

Storing the result

SINTERSTORE / SUNIONSTORE save the result to a new key — handy for caching expensive intersections.

SINTERSTORE active_premium users:premium users:active
EXPIRE active_premium 300

Now SMEMBERS active_premium is O(N) but free until the cache expires.

Iterating safely

Don’t SMEMBERS a set with 10 million entries — it blocks the server. Use SSCAN:

SSCAN big_set 0 COUNT 100

Encoding

Small sets of integers are stored as a sorted intset (compact, sorted array). Larger or mixed sets become a hashtable. Redis swaps automatically.

SADD numbers 1 2 3
OBJECT ENCODING numbers
# "listpack"  (Redis 7) or "intset" (Redis 6)

When sets are wrong

If we need ordering, use a sorted set. If we need counts per item, use a hash with HINCRBY. If cardinality matters but exact membership doesn’t, HyperLogLog is dramatically cheaper at scale.