What you'll learn
Quick Answer
Memcached is a lean, multithreaded, in-memory key-value store designed to do one thing - cache blobs by key - very fast and with minimal operational fuss. Redis is a richer in-memory data store: strings plus lists, hashes, sets, sorted sets, streams, and more, with optional persistence, replication, pub/sub, transactions, and Lua scripting. If you only need to cache serialized values and expire them, Memcached is enough. If you want the cache to also do rate limiting, leaderboards, queues, or session storage that survives a restart, choose Redis.
What each one actually is
Memcached is a cache. You set a key to a value (a string or a serialized blob) with an optional expiry, and you get it back. That is essentially the whole feature set. It has been doing this since 2003, it is small, and it is predictable. Values have a default maximum size of 1MB (configurable).
Redis calls itself an in-memory data structure store, and the distinction matters. A Redis value can be a string, but it can also be a list you push and pop, a hash with fields, a set with membership tests, a sorted set ordered by score, a stream, a bitmap, or a HyperLogLog. Each type has purpose-built commands. Confirmed from the client: a Redis connection exposes hSet, lPush, sAdd, zAdd, xAdd, pSubscribe, expire, and incr, among many others.
So the real question is not "which cache is faster" - both are fast enough that the network round-trip dominates - but "do I want a cache, or a Swiss-army in-memory store?"
Data structures change what you can build
With Memcached, complex operations happen in your application: read the value, deserialize it, modify it, serialize it, write it back. Two requests doing this concurrently can clobber each other unless you use cas (check-and-set).
With Redis, the structure and the operations live in the server. A counter is INCR key - atomic, no read-modify-write race. A leaderboard is a sorted set: ZADD to record scores, ZREVRANGE to get the top 10, all server-side. A rate limiter is INCR plus EXPIRE, or a sliding window with a sorted set. A simple job queue is LPUSH and BRPOP. A recently-viewed list is a capped list with LPUSH + LTRIM.
None of these are possible in Memcached without doing the work in your app and fighting concurrency. This is the single biggest reason teams pick Redis even when they started out just wanting a cache.
Persistence and durability
Memcached is purely in-memory. Restart the process - a deploy, a crash, a config reload - and every key is gone. For a cache this is acceptable: the data is a copy of something authoritative, and the cache refills on the next miss.
Redis can persist. RDB snapshots write a point-in-time dump on an interval; AOF (append-only file) logs every write and replays it on startup, with configurable fsync frequency. You can run with both, one, or neither. This means Redis can hold data you would be unhappy to lose on a restart - user sessions, a queue with in-flight jobs, a computed dataset that takes minutes to rebuild.
The gotcha: persistence is not free. AOF with aggressive fsync costs write latency; RDB snapshots fork the process and briefly use extra memory. And even with AOF, a crash can lose the writes since the last fsync. If you need real durability guarantees, Redis is a convenience, not a replacement for a database.
Memory model and threading
Memcached uses a slab allocator: memory is carved into fixed-size chunks grouped by size class. This makes allocation fast and fragmentation-resistant, but a value that does not fit a slab class wastes the remainder, and memory assigned to one size class is not easily reclaimed for another. Memcached is multithreaded and scales across CPU cores well for high-throughput simple gets and sets.
Redis is famously (mostly) single-threaded for command execution - one core processes commands one at a time, which is why every simple command is effectively atomic. Modern Redis added threaded I/O for reading and writing sockets, and background threads for tasks like freeing memory, but the command loop itself is one thread. This is usually fine because Redis is rarely CPU-bound, but a single slow command (a big KEYS *, a large SORT) blocks everyone. Redis's memory use is more flexible than Memcached's slabs, and it offers several maxmemory-policy eviction strategies (LRU, LFU, TTL-based, random).
Scaling and the extras
Memcached scales horizontally by client-side sharding: the client hashes the key and picks a server. Add nodes and you get more memory and throughput, but there is no built-in replication - a node dying means its share of the cache is cold until it refills.
Redis has Redis Sentinel for automatic failover of a primary-replica setup, and Redis Cluster for sharding with replication built in, so a node failure does not lose data if a replica is promoted. Redis also has pub/sub for messaging, MULTI/EXEC transactions, Lua scripting for atomic multi-step operations, keyspace notifications, and modules.
All of that is capability Memcached deliberately does not have. Memcached's answer is: that is not a cache's job, and keeping the surface small keeps it simple and reliable.
Which to choose
Choose Memcached when: you need a pure look-aside cache for serialized values; you want the simplest possible thing to operate; your access pattern is high-volume simple gets and sets where multithreading helps; and losing the whole cache on restart is fine.
Choose Redis when: you want the cache to also do counters, rate limiting, leaderboards, queues, or session storage; you need data to survive a restart; you want built-in replication and failover; or you expect the caching layer's role to grow over time. In practice this covers most new projects, which is why Redis is the more common default today.
A reasonable rule: start with Redis unless you have a specific reason to want Memcached's minimalism. The feature headroom costs you little and you will probably use some of it within a year.
