The data structure server hiding behind your caching layer – and where it quietly does its best work
Ask ten engineers what Redis is for, and at least nine will say some version of “we cache stuff in it.” They’re not wrong — caching is Redis’s most famous job, and a genuinely great one. But it’s also the least interesting thing Redis does, and treating it as the whole story means most teams quietly ignore 80% of what they’re already paying to run.
Redis stands for REmote DIctionary Server, and the name is the whole clue: it was never designed as a cache with extra steps. It was designed as an in-memory data structure server — and the cache is just one of the simplest things you can build once you have that.
The Cache-Only Stereotype
The pattern almost everyone reaches for first is cache-aside: check Redis before hitting the database, and backfill Redis when you get a miss.
Figure 1 – The cache-aside pattern: legitimate, common, and one narrow slice of what Redis can do.
There’s nothing wrong with this pattern — it’s a genuinely good use of Redis, and probably belongs in most systems that read the same data far more often than they write it. The problem isn’t that teams use Redis this way. It’s that many teams use Redis only this way, and then reach for a second, third, and fourth piece of infrastructure to solve problems Redis was already sitting there ready to handle.
What Redis Actually Is
Under the hood, every value in Redis isn’t just a blob of bytes behind a key — it’s a typed data structure with its own purpose-built commands. That’s the part “just a cache” leaves out entirely.
Figure 2 — Nine data types, each with commands built for a specific shape of problem.
Once you see Redis this way, a lot of infrastructure decisions get simpler. You don’t need a separate rate-limiting service, a separate leaderboard database, or a separate pub/sub broker for lightweight use cases — you likely need a Redis command you haven’t tried yet.
Where Redis Quietly Does Its Best Work
Rate Limiting
A sliding or fixed-window rate limiter is famously just two commands: INCR to bump a per-user counter, and EXPIRE to let that counter reset itself. No cron job, no background sweeper — Redis handles the expiry natively.
INCR rate:user123
EXPIRE rate:user123 10
# if the returned count > limit, reject the request
Figure 3 — A fixed-window limiter: two commands, one TTL, no extra service.
Leaderboards and Ranking
Sorted sets keep every member ordered by score automatically, with inserts, updates, and range reads all running in O(log N). No pulling rows into application memory to sort them yourself.
ZADD leaderboard 9400 "Zoya" 8600 "Ravi" ZREVRANGE leaderboard 0 2 WITHSCORES # -> top 3 players, already ranked
Figure 4 — A live, always-sorted ranking with no application-side sort step.
Distributed Locks
A single SET key value NX PX 30000 is enough to implement a basic mutual-exclusion lock across multiple app instances: it only succeeds if no one else holds the key, and it auto-expires so a crashed process can’t hold the lock forever. For correctness across multiple independent Redis nodes, Redis’s own Redlock algorithm formalizes the same idea with quorum acknowledgement.
SET lock:invoice-482 worker-7 NX PX 30000
# only one worker gets "OK" — everyone else gets nil and backs off Pub/Sub and Lightweight Messaging
For simple fan-out, PUBLISH / SUBSCRIBE gets a message to every currently-connected listener with almost no setup. For anything that needs a durable, replayable log — consumer groups, at-least-once delivery, catching up after a restart — Streams are the closer analogue to a message queue:
XADD orders:events * order_id 4821 status "paid"
XREAD COUNT 10 STREAMS orders:events 0
# durable, ordered, and replayable — unlike PUBLISH/SUBSCRIBE Streams comfortably handle moderate-throughput event pipelines without introducing a whole new broker into the stack.
Real-Time Analytics
Need an approximate count of unique visitors across millions of events without storing every single one? HyperLogLog gives you a 99%-accurate distinct count using a fixed ~12KB of memory, regardless of how many items you feed it. Need a compact daily-active-user flag per user? A Bitmap can track a year of yes/no activity for a million users in a few megabytes.
PFADD unique_visitors:2026-08-30 user_9182 user_4471
PFCOUNT unique_visitors:2026-08-30
# approximate distinct count, ~0.81% standard error The Ways Teams Actually Misuse Redis
The irony is that the same teams under-using Redis’s feature set are often simultaneously misusing the cache half of it. The most common failure modes:
- No TTL on cache keys. Values get written once and never expire, and Redis's memory footprint grows quietly until an eviction policy starts dropping data you assumed was safe — or until the instance runs out of RAM entirely.
- Running KEYS * in production. It's O(N) and single-threaded-blocking — on a large keyspace it can freeze every other client for seconds. SCAN exists for exactly this reason and doesn't block.
- Treating Redis as a system of record with default settings. Out of the box, Redis is tuned for speed, not durability. If Redis is holding data you can't afford to lose, that's a deliberate persistence decision (more below), not a default you can ignore.
- Single instance, no replica, no failover. A crash means every session, lock, and queued job disappears at once. Sentinel or Cluster mode exists specifically so this isn't a single point of failure.
- Storing large blobs as values. Redis is memory-resident by design — stuffing multi-megabyte payloads into it is an expensive way to store what a blob store or the database itself would hold far more cheaply.
Making It Durable: RDB vs AOF
The “Redis loses data if it restarts” concern is really a configuration question, not an inherent limitation. Redis offers two persistence mechanisms, and you choose based on what you’re actually storing.
Figure 5 — RDB snapshots are cheap and fast to restore; AOF logs every write for durability.
RDB periodically writes a compact point-in-time snapshot to disk — fast to load on restart, but anything written since the last snapshot is gone if the process dies. AOF appends every write operation to a log, so recovery can replay right up to (or very near) the last write — at the cost of a larger file and slightly slower restarts.
In Practice
Most production Redis deployments enable both: RDB for fast, cheap full recoveries, and AOF for the durability guarantee that matters when Redis is holding something more meaningful than a disposable cache entry — a job queue, a rate-limit ledger, or session data users would notice losing.
When Redis Is Not the Right Tool
None of this makes Redis a replacement for a relational database, a data warehouse, or a heavyweight message broker. It’s excellent at what it’s built for, and worth being honest about what it isn’t:
- Complex relational queries. Multi-table joins, ad-hoc filtering across relationships, and rich query planners are a relational database's job, not Redis's.
- Strict, multi-entity ACID transactions. Redis transactions (MULTI/EXEC) queue commands atomically but don't offer the rollback and isolation guarantees a relational engine gives you across several tables.
- Data much larger than affordable RAM. Redis keeps the active dataset in memory — that's the whole source of its speed, and also the reason storing terabytes of cold data in it gets expensive fast.
- Extreme-scale durable messaging. Redis Streams handle moderate-throughput event pipelines well, but at Kafka-scale partitioned, multi-consumer-group, retain-forever workloads, a purpose-built broker is still the right call.
Reach or Redis vs. Reach for Something Else
Reach for Redis
- Sub-millisecond reads on hot data
- Counters, rate limits, feature flags
- Leaderboards / ranked data
- Ephemeral session or lock state
- Pub/Sub or moderate-throughput streams
- Data that fits comfortably in RAM
Reach for Something Else
- Complex multi-table joins
- Strict multi-entity ACID transactions
- Data far larger than affordable RAM
- Long-term system of record with heavy audit/compliance needs
- Extreme-scale durable messaging (prefer Kafka / RabbitMQ)
- Ad-hoc analytical queries over historical data
Figure 6 — A quick gut-check for whether the problem in front of you is actually a Redis problem.
The Interview Question You Should Actually Prepare For
If an interviewer asks, “Is Redis a database?” resist the reflex to answer with a flat yes or no — the honest answer is more useful than either.
A Stronger Answer
“Redis is an in-memory data structure server that can be used as a cache, a primary datastore, a message broker, or all three at once, depending on how you configure persistence and what durability guarantees you actually need. Calling it just a cache undersells the data structures; calling it a full database replacement ignores what it deliberately doesn’t do, like relational joins and heavyweight transactions.”
And if the follow-up is “How would you make Redis durable?” — that’s your cue to walk through RDB vs. AOF, and why most real deployments run both.
The Big Picture
Redis earned its reputation as a cache because caching is the easiest use case to reach for and the fastest to explain. But the underlying engine was built for something broader — a small, extremely fast toolbox of data structures that happens to make an excellent cache as one of its many applications.
The question worth asking isn’t “should we cache this in Redis?” It’s “is there a Redis data structure that already models this problem?”
Rate limiters, leaderboards, locks, lightweight queues, and approximate counters are all sitting one command away in infrastructure most teams already run — and are already paying for. The most misused thing about Redis isn’t a misconfiguration. It’s how rarely teams ask what else it can do.
Ready to Understand Systems Beyond the Basics?
Redis is more than a cache, and real-world engineering is about understanding why a tool exists, where it fits, and when another architecture is the better choice.
Build practical skills in distributed systems, caching, scalability, architecture, and real-world engineering trade-offs with CodeKerdos.