What Is Redis, and Why Do Developers Use It for Caching?
Redis shows up in an enormous share of production architectures for one core reason: reading from RAM is dramatically faster than disk. Here's what it actually is, its real data structures, and where caching bugs actually live.
TCTechToolsCenter TeamRedis shows up in an enormous share of production web architectures, almost always for the same underlying reason: reading data from RAM is dramatically faster than reading it from a disk-backed database, and Redis is purpose-built as an in-memory data store that does exactly that, with enough additional structure to be genuinely useful beyond a simple key-value cache.
What Redis actually is
Redis (REmote DIctionary Server) is an open-source, in-memory data structure store, most commonly used as a cache, a message broker, or a lightweight database in front of (or alongside) a primary, disk-backed database like PostgreSQL or MySQL. The core idea is straightforward: instead of hitting your primary database for every single read — even ones for data that barely changes — you store a copy of frequently-accessed data in Redis's memory, where retrieving it takes microseconds rather than the milliseconds a disk-backed query typically takes.
Sponsored
Why caching with Redis specifically, rather than just querying the database directly
A relational database is optimised for consistency, complex queries and durable storage — genuinely important properties, but ones that come with real overhead per query, especially under high concurrent load. For data that's read far more often than it changes (a user's profile information, a product catalog page, a computed leaderboard), repeatedly re-querying and re-computing that same result from the primary database on every single request wastes both database capacity and response time. Storing the computed result in Redis once, then serving subsequent requests directly from memory until the underlying data actually changes, cuts both database load and response latency significantly — this pattern, called cache-aside, is the most common way Redis gets used in a typical web application.
Redis's actual data structures — more than just key-value
- Strings — the simplest structure, a key mapped to a single value (text, a serialized JSON blob, a number) — the most common case for basic caching.
- Hashes — a key mapped to a set of field-value pairs, useful for storing an object (a user record with several fields) without needing to serialize/deserialize the whole thing on every access.
- Lists — ordered collections, useful for things like a recent-activity feed or a simple queue.
- Sets and Sorted Sets — unordered and ordered unique collections respectively; sorted sets specifically power common use cases like real-time leaderboards, since members are automatically kept ordered by an associated score.
- Streams — an append-only log structure, used for building simple event-streaming or message-queue-like systems directly within Redis.
Session storage — a genuinely common Redis use case
Beyond generic caching, Redis is extremely commonly used to store user session data for web applications — particularly for applications running multiple backend server instances behind a load balancer, where a session stored only in one server's local memory would be lost the moment a load balancer routes a subsequent request to a different server instance. Storing sessions in a shared Redis instance that every backend server can read from solves this cleanly, letting any server instance handle any request without needing sticky sessions or in-memory session replication between servers.
Redis as a message broker / pub-sub system
Beyond caching, Redis includes a built-in publish/subscribe (pub-sub) messaging pattern, letting one part of a system publish a message to a named channel and any number of other parts subscribe to receive it in real time — useful for lightweight real-time features (live notifications, chat message delivery) without needing to stand up a separate, heavier message-queue system. For genuinely durable, guaranteed-delivery messaging with more sophisticated queuing semantics, a dedicated message broker (covered in our message queue explainer) is usually the more robust choice — Redis's pub-sub is fire-and-forget by default, meaning a message published while no one is subscribed is simply lost, unlike a proper durable queue.
Rate limiting with Redis
A very common, practical use case: implementing API rate limiting using Redis's atomic increment operations to track how many requests a specific client has made within a time window, since Redis's speed and support for atomic counter operations make it well-suited to handling this check on every single incoming request without becoming a bottleneck itself.
Persistence — Redis isn't purely volatile by default configuration
Because Redis is in-memory, a naive assumption is that all data is lost the instant the server restarts — but Redis actually supports optional persistence mechanisms: RDB (periodic point-in-time snapshots written to disk) and AOF (Append-Only File, logging every write operation for more granular recovery), either or both of which can be enabled depending on how much data-loss risk is acceptable for a given use case. For pure caching (where losing the cache just means the next request falls back to the primary database and repopulates it), persistence is often disabled entirely, since the cached data is disposable by design. For Redis used as a more primary data store (session data, real-time counters that matter), enabling persistence is usually the right call.
Cache invalidation — the genuinely hard part
There's a well-known engineering saying that cache invalidation is one of the two genuinely hard problems in computer science, and it holds true for Redis-based caching as much as any other caching layer: the moment underlying data changes, the cached copy becomes stale, and deciding exactly when and how to update or evict that stale cache entry is where real caching bugs live. Common strategies include a Time-To-Live (TTL) on cached entries (accepting some staleness for a bounded window, simple to implement), explicit invalidation (actively deleting or updating the cache entry the moment the underlying data changes, more precise but requires the application to remember to do it everywhere relevant), and write-through caching (updating the cache and the database together in the same operation, keeping them always in sync at the cost of slightly more complex write logic).
Redis vs Memcached — the other well-known in-memory cache
Memcached is Redis's older, simpler sibling — a pure, multithreaded key-value cache with none of Redis's richer data structures, persistence options, or pub-sub capability. For a genuinely simple caching need with nothing beyond basic key-value get/set, Memcached's simplicity is a real, valid advantage; for anything needing structured data (hashes, sorted sets), pub-sub messaging, or optional persistence, Redis's broader feature set is generally the more capable and now far more commonly chosen option in new projects.
Common mistakes when introducing Redis into a project
- Caching data without a clear invalidation strategy, leading to stale data being served indefinitely or until a restart clears it.
- Storing genuinely critical data in Redis without enabling any persistence, then losing it entirely on an unexpected restart.
- Using Redis pub-sub for messages that genuinely need guaranteed delivery, not realising messages are lost if no subscriber is listening at publish time.
- Setting no TTL on cache entries at all, letting Redis's memory usage grow indefinitely as the dataset of "things ever cached" keeps expanding.
- Treating Redis as a drop-in replacement for a primary database rather than a complementary layer in front of one.
Redis eviction policies — what happens when memory fills up
Because Redis stores everything in RAM, available memory is a real, finite constraint, and Redis supports several configurable eviction policies dictating what happens once memory limits are reached — options include evicting the least-recently-used keys first (a common default for pure caching workloads), evicting keys with the shortest remaining TTL first, or simply refusing new writes once the limit is hit (more appropriate when Redis is holding data that must not be silently discarded). Choosing the right eviction policy for a specific workload matters — a cache-only deployment generally wants old, less-relevant entries evicted automatically, while a deployment using Redis for anything more critical needs to think carefully about whether silent eviction is ever an acceptable behaviour at all.
Redis Cluster and replication for scale and reliability
A single Redis instance is a single point of failure and a hard ceiling on both memory capacity and throughput — for production systems that can't tolerate either limitation, Redis supports replication (one or more read replicas mirroring a primary instance, providing redundancy and spreading read load) and Redis Cluster (sharding data automatically across multiple nodes, letting the total dataset size and throughput scale beyond what a single machine could handle). Introducing either adds real operational complexity — failover behaviour, data consistency during a primary failure, and cluster rebalancing all need to be understood — which is why many teams start with a single managed Redis instance and only move to replication or clustering once genuine scale or reliability requirements make it necessary, rather than adopting the added complexity upfront.
Managed Redis vs self-hosting
Most cloud providers (AWS ElastiCache, Google Cloud Memorystore, Azure Cache for Redis) and dedicated vendors (Redis Cloud, Upstash) offer managed Redis instances that handle provisioning, patching, backups, and often replication/clustering configuration automatically — a meaningfully lower operational burden than self-hosting Redis on your own servers, particularly for a smaller team without dedicated infrastructure expertise. Self-hosting remains a reasonable choice specifically when cost at scale, very particular configuration needs, or existing infrastructure investment make it the more practical option, but for most new projects, starting with a managed offering avoids a real category of operational work (patching, backup verification, failover testing) that a managed service handles as part of its baseline offering.
Redis's single-threaded execution model
A detail that surprises developers coming from a multithreaded programming background: Redis's core command execution is single-threaded — each command runs to completion before the next one starts, with no risk of two commands racing against each other mid-execution. This design choice trades away multi-core parallelism for genuinely simpler semantics: operations that would otherwise need careful locking in a multithreaded system (like an atomic increment used for rate limiting) are simply atomic by default in Redis, since nothing else can run concurrently to interfere. Newer Redis versions have introduced limited multithreading for specific background tasks (like I/O handling), but the core command execution guarantee remains single-threaded, which is precisely why patterns like atomic counters and simple locks work so reliably without extra coordination logic in the application itself.
Redis data types beyond the basics — HyperLogLog and Geospatial
Beyond the commonly used strings, hashes, lists and sets, Redis includes a couple of more specialised structures worth knowing exist: HyperLogLog, a probabilistic data structure for estimating the count of unique items (like unique visitors to a page) using a small, fixed amount of memory regardless of how many actual items are counted — trading a small, statistically bounded margin of error for dramatic memory savings compared to tracking every unique item exactly. Geospatial indexes let you store coordinates and efficiently query for items within a radius or sorted by distance — useful for location-based features (finding nearby stores or drivers) without needing a separate, dedicated geospatial database for that specific query pattern.
When Redis is the wrong tool
Despite its versatility, Redis isn't the right fit for every job — it's not designed as a system of record for data requiring complex relational queries, joins, or strict ACID transactional guarantees across multiple operations the way a relational database provides natively. Reaching for Redis to store data that genuinely needs those relational guarantees, purely because it's already in the stack for caching, tends to create more problems than it solves — the right mental model is Redis as a fast, complementary layer for specific access patterns (caching, sessions, counters, real-time pub-sub), sitting alongside a primary database designed for the data's actual structural and consistency requirements, not as a universal replacement for one.
A practical first use case if you're adding Redis to a project
For a team introducing Redis for the first time, caching the result of a specific, genuinely expensive and infrequently-changing query or computation — rather than attempting to cache broadly across the entire application on day one — is the most manageable starting point. Picking one clear, measurable bottleneck, adding a TTL-based cache in front of it, and confirming the actual latency and database-load improvement gives a team a concrete, low-risk first success with the tool, and a much better intuition for cache invalidation in practice, before expanding Redis usage further into sessions, rate limiting, or other parts of the system where the payoff and the risk of getting invalidation wrong are both genuinely higher.
Tools used in this article
Sponsored
Frequently asked questions
Most commonly as a cache in front of a primary database, for session storage across multiple backend servers, as a lightweight pub-sub message broker, and for fast operations like rate-limiting counters.
TechToolsCenter Team
Product & Tools
The team behind TechToolsCenter — building fast, private, browser-based tools and writing practical guides on how to get the most out of them.
Related articles
What Is a Message Queue, and When Do You Need One?
A message queue lets one part of a system hand off work to another without either side needing to be online at the same moment — here's how producers, consumers and dead-letter queues actually fit together.
What Is a CDN, and How Does It Actually Work?
A CDN doesn't make your server faster — it puts copies of your content physically closer to the people requesting it, so the distance data has to travel shrinks instead of the server itself changing.
REST vs GraphQL: What's Actually Different, in Plain English
Both fetch data over HTTP. The real difference is who decides what comes back in the response — the server, or the client asking the question.