The short answer
Quick answer: Redis is fast for four reasons. First, it keeps all data in memory, so there is no disk access on the read path. Second, it executes commands on a single thread, so it needs no locks and wastes no time on contention. Third, it uses I/O multiplexing to serve tens of thousands of connections from that one thread. Fourth, its data structures are purpose-built and compact, so most commands do a tiny amount of work. A single Redis instance commonly handles on the order of a hundred thousand operations per second with sub-millisecond latency.
Also Read: How Database Replication Works: Leaders and Replicas - How To's
Reason 1: Everything lives in RAM
Reading from memory takes around 100 nanoseconds. Reading from even a fast SSD takes tens to hundreds of microseconds. The latency numbers every programmer should know make the gap obvious.
A traditional database is designed around disk: its data structures, caching and query execution all exist to minimise disk reads. Redis skips the problem entirely. Every key is in memory, and a lookup is a hash table access followed by a pointer or two.
The obvious limit: your data set must fit in RAM, and RAM is far more expensive than disk. See why we need both RAM and storage.
Reason 2: A single thread runs your commands
It sounds like a weakness. For Redis's workload, it is a strength.
Multi-threaded databases spend effort protecting shared data: locks, latches, and the cache effects of several cores touching the same memory. Redis commands are so short, often well under a microsecond of real work, that the coordination overhead of threads would cost more than the work itself.
With one thread:
- No locks and no deadlocks.
- No context switching between worker threads.
- Every command is atomic. Nothing else can run in the middle of an
INCRor a Lua script. This makes Redis very easy to reason about.
The bottleneck in a typical Redis deployment is the network and memory, not the CPU.
Redis is not strictly single-threaded any more. Since version 6 it can use extra threads to read from and write to sockets, and it uses background threads for tasks such as freeing large objects. Command execution itself remains on one thread.
Reason 3: I/O multiplexing
How does one thread serve ten thousand clients? The same way Node.js and Nginx do: with an event loop.
Redis asks the operating system, using epoll on Linux or kqueue on BSD and macOS, to report which sockets have data ready. It then loops:
- Ask the kernel which connections are ready.
- Read each pending command.
- Execute it.
- Write the reply.
No thread ever sits blocked waiting for a slow client. Idle connections cost almost nothing.
Reason 4: Efficient data structures
Redis is often called a key-value store, but the values are rich data structures, described in the Redis data types documentation. Each is implemented for speed and compactness.
Also Read: The N+1 Query Problem: What It Is and How to Fix It
| Type | What it is | Typical uses |
|---|---|---|
| String | Bytes, text or a number | Caching, counters, flags |
| Hash | Field-value pairs under one key | Objects, user sessions |
| List | Ordered sequence, fast at both ends | Queues, recent items |
| Set | Unique members | Tags, unique visitors |
| Sorted set | Members ordered by a score | Leaderboards, rate limiting, priority queues |
| Stream | Append-only log with consumer groups | Event streams, messaging |
| Bitmap, HyperLogLog | Bit arrays; approximate distinct counts | Feature flags, counting unique users cheaply |
| Geospatial | Points indexed by location | "Find nearby" |
Details that matter for performance:
- The main key space is a hash table that resizes incrementally, a few buckets per operation, so a resize never causes a long pause.
- Sorted sets combine a hash table with a skip list, giving fast lookups by member and fast range queries by score.
- Small collections use compact encodings. A hash with a few fields is stored as one contiguous block rather than a full hash table, which saves memory and is friendly to the CPU cache. Redis switches encoding automatically as the collection grows.
The right command on the right structure replaces work you would otherwise do in application code. A leaderboard is one ZADD and one ZREVRANGE.
Reason 5: A simple protocol and pipelining
Redis's wire protocol is plain and cheap to parse. Clients can also pipeline: send many commands without waiting for each reply, then read all the replies together. Since network round trips usually dominate, pipelining can multiply throughput several times over.
Related tools:
MGET/MSETfetch or set many keys in one command.MULTI/EXECrun a group of commands as a transaction.- Lua scripts and functions run logic on the server atomically, avoiding round trips.
But is it durable?
Redis offers two persistence mechanisms, explained in the Redis persistence documentation:
| Mechanism | How it works | Trade-off |
|---|---|---|
| RDB snapshots | Periodically fork the process and write the whole data set to a file | Compact and fast to restore; lose changes since the last snapshot |
| AOF (append-only file) | Log every write command; fsync every second by default | Lose at most about a second; larger files |
Snapshots rely on the operating system's copy-on-write behaviour: the child process sees a frozen view of memory while the parent continues to serve requests. The append-only file works on the same principle as a write-ahead log.
With default settings, Redis can lose the last moments of writes in a crash. That is the deliberate trade for speed, and it is why Redis is usually a cache or secondary store, with a durable database as the source of truth.
The trade-offs
- Memory bound. When memory fills, Redis either rejects writes or evicts keys according to a policy such as least recently used.
- Slow commands block everyone. Because there is one thread, a command that scans a million items delays every other client. Avoid
KEYS *in production; useSCAN. Watch for commands that are O(n) on large collections. - One core per instance. To use more cores or more memory than one machine has, run Redis Cluster, which shards keys across nodes.
- Replication is asynchronous by default, so a failover can lose recent writes.
What it is used for
- Caching database queries and rendered pages. See caching strategies.
- Session storage.
- Rate limiting with counters and sorted sets. See how rate limiters work.
- Queues and background jobs.
- Leaderboards and counters.
- Pub/sub and streams for real-time messaging.
- Distributed locks, with care. See how distributed locks work.
Frequently asked questions
Is Redis single-threaded?
Command execution is. Recent versions use additional threads for network I/O and background clean-up.
Is Redis a database or a cache?
Both. It is an in-memory data store with optional persistence. Most teams use it as a cache or for specialised data alongside a primary database.
What happens when Redis runs out of memory?
Depending on the configured policy, it either returns errors on writes or evicts keys, for example the least recently used ones.
How is Redis different from Memcached?
Memcached is a simpler, multi-threaded key-value cache for strings. Redis adds rich data structures, persistence, replication, scripting and messaging.
Conclusion
Redis is fast because it is simple in the right places: data in memory, one thread with no locks, an event loop for I/O, and data structures tuned for the job. Those same choices define its limits. Keep commands small, keep the data set within RAM, and pair it with a durable store for anything you cannot afford to lose.
Related articles
- Caching Strategies: Write-Through, Write-Back, and Cache-Aside
- What Is the Event Loop and Why Is Node.js Single-Threaded?
- How Hash Maps Achieve O(1) Lookups
- How Rate Limiters Protect APIs From Abuse
