Data types and the commands that matter

Strings, lists, hashes, sets and sorted sets — what each one is for, and why the O(N) commands are a production hazard.

Strings and lists

A Redis string holds up to 512 MB of binary-safe bytes, which means it also stores JSON, a serialised object, or a counter. Because command execution is single-threaded, operations like INCR and SETNX are atomic without any locking.

SET   user:42:name "Ada" EX 3600       # with a one-hour TTL
SETNX lock:job:9 worker-3              # only if the key does not exist
GET   user:42:name
APPEND user:42:name " Lovelace"

INCR  stats:pageviews                  # atomic, creates the key at 0 first
INCRBY quota:42 -1

MSET a 1 b 2
MGET a b

LPUSH queue:email "m-1" "m-2"          # push to the head
RPUSH queue:email "m-3"
LRANGE queue:email 0 -1                # read without removing
LPOP  queue:email 2                    # pop and return up to two
LTRIM notifications:42 0 99            # keep only the newest 100
  • Lists are linked lists: pushes and pops at either end are O(1), indexing into the middle is O(N).
  • LTRIM after a push is the standard way to keep a capped feed or a bounded log per user.
  • BLPOP and BRPOP block until an element arrives — the classic simple queue, with the durability caveat covered later.
  • Key names are a flat namespace; the colon convention (object:id:field) exists purely so humans and SCAN patterns stay readable.

Hashes, sets and sorted sets

HSET   user:42 name "Ada" plan "pro" logins 12
HINCRBY user:42 logins 1
HGETALL user:42
HRANDFIELD user:42 -1

SADD    post:9:likes 42 77 101
SISMEMBER post:9:likes 42
SINTER  post:9:likes post:12:likes     # users who liked both
SCARD   post:9:likes

ZADD    leaderboard 1500 alice 1200 bob 900 carol
ZINCRBY leaderboard 50 bob
ZREVRANGE leaderboard 0 9 WITHSCORES   # top ten
ZRANGEBYSCORE leaderboard 1000 +inf
ZRANK   leaderboard alice              # 0-based position
TypeModelTypical use
StringOne valueCache entries, counters, locks, JSON blobs
ListOrdered sequence, fast at both endsQueues, activity feeds, capped logs
HashField/value map per keyObjects whose fields change independently
SetUnordered unique membersTags, membership tests, intersections
Sorted setUnique members with a scoreLeaderboards, rankings, rate limiters, priority queues
StreamAppend-only log with IDsDurable queues and consumer groups
Bitmap / HLLBit or cardinality sketchPresence flags, unique-count estimates

A sorted set scores lexicographic order too: when every member has the same score, ZRANGEBYLEX answers range queries on strings, which is how autocomplete indexes are often built.

Atomicity and the O(N) trap

MULTI
INCR  stats:orders
ZADD  leaderboard 10 alice
EXEC                     # both run, in order, with nothing in between

EVAL "return redis.call('GET', KEYS[1])" 1 user:42:name

SCAN 0 MATCH user:42:* COUNT 100      # safe cursor-based iteration
OBJECT ENCODING leaderboard           # listpack or skiplist?
MEMORY USAGE user:42
  • MULTI/EXEC queues commands but does not roll back: if one command fails at runtime the others still execute. Use a Lua script when you need all-or-nothing logic.
  • A Lua script runs atomically, which makes it the right tool for compare-and-set sequences that must not interleave.
  • KEYS pattern, HGETALL, SMEMBERS, LRANGE key 0 -1 and FLUSHALL are O(N) and block every other client during execution.
  • Use the incremental scan family — SCAN, HSCAN, SSCAN, ZSCAN — instead of the O(N) variants in production code.
⚠️
Command execution is single-threaded, so one slow command stalls the entire instance for every client. Run SLOWLOG GET 25 and LATENCY DOCTOR when latency spikes; the culprit is almost always an O(N) command over a large key.

FAQ

Why does Redis not use disk like a normal database?
It is designed to serve data from memory, where reads and writes cost microseconds. Disk is used for durability and restarts, not for serving reads, which is why everything must still fit in RAM.
How do I store an object?
A hash when individual fields are updated separately and the object is small; a serialised string when you always read or write the whole value. Hashes also allow partial reads without transferring everything.

Expiry and caching patterns Pub/sub, queues and persistence

Last refreshed 2026-09-18.