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
{1,2,3,4,5,6}
{4,5,6}
{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.