Redis anti-patterns.

KEYS in prod

KEYS user:*

Blocks server for size of dataset. Use SCAN.

SMEMBERS on huge set

SMEMBERS huge_set

Returns all members. Use SSCAN.

ZRANGE 0 -1 on huge zset

Returns everything. Use LIMIT and pagination.

Huge value

Single 100MB string blocks server during read.

No TTL on cache

Memory leak.

Using lists as queues without trimming

Lists grow unbounded.

Pub/sub for important events

Lost on disconnect. Use Streams.

DELETE huge keys

DEL on huge set: blocking. Use UNLINK (async).

Storing serialized objects when hashes work

SET user:1 '{"name":"a","age":30}'

vs

HSET user:1 name "a" age 30

Hash easier to read fields, often smaller.

Multi-DB usage

SELECT 1
SET ...

Multi-DB confusing + not cluster-compatible. Use key prefixes.

Long-running Lua scripts

Block entire server. Keep scripts fast.

MONITOR in prod

Logs every command. Heavy. Debugging only.

FLUSHALL by accident

DBSIZE → 1000000
FLUSHALL → 0

Add ACL restrictions.

Same Redis for everything

Cache + queue + sessions + pubsub. Noisy neighbor. Separate by use.

Persistence on cache-only

If pure cache: save "" + appendonly no. Less I/O.

No max-memory

maxmemory 0  # unlimited; default

OOM kills.

Forgetting WAIT for durability

SET k v
# Replica might not have it; primary crash → lost.
WAIT 1 1000

SUNIONSTORE huge sets

Materializes union. Expensive. Use SUNION + iterate.

Caching things that change

Cache without invalidation → stale data forever.

Ignoring cluster hash tags

Multi-key ops fail with CROSSSLOT. Use {tag}.

Per-call connections

Open + close per request → slow. Use pool.

Treating Redis as primary store without persistence

Restart = lost data.

Trusting client clock

ttl = expires_at - time.time()  # client time

Drift between clients/server. Use server TTL (EXPIRE).

Storing large structured data without RedisJSON

Repeated parse + write of huge JSON strings.

Manual sharding without cluster

Roll your own keyhash → no rebalancing. Use Cluster.

Using lists for latest N without LTRIM

r.lpush("recent", item)
# missing: r.ltrim("recent", 0, 99)

Grows forever.

Ignoring slow commands

If SLOWLOG shows N seconds for SCAN, the COUNT is too high.

INCR for floats

Use INCRBYFLOAT.

TTL race

GET k
# expires here
SET ... with computed value

Use Lua for atomic.

Common mistakes

  • Treating Redis as DB without persistence.
  • Mixing cache + queue keys.
  • No monitoring until production fire.
  • Using Redis for things SQL is better at (relational queries).
  • Premature cluster (single Redis fine to ~50GB).

Read this next

If you want my Redis review checklist, it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .