What Is a Redis Cache?

A Redis cache stores frequently accessed data in memory so that an application can serve it in microseconds instead of querying a slower disk-backed database. It is the single most common way Redis is deployed, and the same applies to Valkey, the open-source fork that speaks the same protocol and supports the same commands. Everything on this page works identically on both.

What is a Redis cache?

A Redis cache is a Redis or Valkey instance used to hold a copy of data that is expensive to produce. When a request arrives, the application looks in the cache first. If the data is there, it is returned immediately. If it is not, the application falls back to the original source, stores the result in the cache, and returns it.

The defining property is that a cache holds derived data. Something else owns the truth, so the cache can be discarded at any point without permanent loss. That distinguishes it from an in-memory database, where the data in memory is the system of record and durability becomes a requirement rather than an option.

The word cache is also used for the hardware caches sitting between a CPU and main memory; see cache memory for that sense of the term. The principle is the same, but the scale is nanoseconds rather than milliseconds.

The data typically worth caching includes expensive database queries and joins, user session state, API responses from slow third-party services, rendered fragments, and computed results such as rankings or aggregates.

How caching in Redis and Valkey works

At its simplest, a cache read is a GET and a cache write is a SET. What makes Redis more capable than a plain key-value cache is that values are not limited to opaque strings. Because it is a data-structure store, a cached value can be a hash, list, set, sorted set, or JSON document, and individual fields can be read or updated without fetching and rewriting the whole entry. Incrementing a counter inside a cached hash is one command, not a read-modify-write cycle.

Caching can also happen on the client side. With client-side caching, sometimes called tracking, the server notifies connected clients when a key they have cached locally changes, so an application can hold a small local copy without serving stale data.

The cache-aside pattern

Cache-aside, also called lazy loading, is the default pattern and the one most applications should start with: the application checks the cache, falls through to the database on a miss, populates the cache, and returns the value. The alternatives change who performs that work — with read-through and write-through caching the cache itself talks to the database, and with write-behind the database update is deferred and batched. A fuller treatment of each is in our guide to Java caching strategies.

RBucket<User> bucket = redisson.getBucket("user:" + id);

User user = bucket.get();
if (user == null) {
    user = userRepository.findById(id);
    bucket.set(user, Duration.ofMinutes(10));
}
return user;

Expiration and TTL

Almost every cache entry should have an expiry. A time to live bounds how stale a value can get and keeps memory from filling with entries nobody reads. Set it when you write the key rather than relying on eviction to clear space later.

RMapCache<String, User> cache = redisson.getMapCache("users");

// per-entry TTL, which plain Redis hashes cannot express
cache.put("123", user, 10, TimeUnit.MINUTES);

// TTL plus a maximum idle time
cache.put("456", user, 30, TimeUnit.MINUTES, 5, TimeUnit.MINUTES);

Choosing a TTL is a judgement about tolerable staleness, not a performance setting. Where correctness matters more than hit rate, pair a longer TTL with explicit cache invalidation on write.

Eviction policies

When a cache reaches its maxmemory limit, the eviction policy decides what gets removed. Redis and Valkey offer eight, set through maxmemory-policy:

  • noeviction - reject writes once memory is full rather than discarding anything.
  • allkeys-lru - evict the least recently used key. The usual choice for a general-purpose cache.
  • allkeys-lfu - evict the least frequently used key. Better when a stable hot set is read repeatedly.
  • allkeys-random - evict at random.
  • volatile-lru, volatile-lfu, volatile-random - the same three, restricted to keys that have a TTL set.
  • volatile-ttl - evict the key closest to expiring.

The volatile-* policies only consider keys with an expiry, so if nothing has a TTL they behave like noeviction and writes start failing. See cache eviction for how each policy behaves under load.

How it compares to Memcached

Memcached is the other well-known in-memory cache. For the simplest workloads the two are close, but Redis and Valkey add structured values, configurable eviction, persistence, replication, and clustering that Memcached does not provide natively. Memcached keeps an edge for small, uniform, purely ephemeral values under heavy multi-threaded load. The full breakdown across data structures, threading, clustering, and Java client support is in Redis vs. Memcached.

Caching in Java with Redisson

Redisson is a Java client that exposes Redis and Valkey through familiar Java interfaces, so a cache looks like a Map rather than a series of commands. Beyond the remote cache, it can hold a local copy of hot entries inside the application's own heap, avoiding the network round trip entirely for the most frequently read keys.

RLocalCachedMap<String, Integer> map = redisson.getLocalCachedMap("test", LocalCachedMapOptions.defaults());

String prevObject = map.put("123", 1);
String currentObject = map.putIfAbsent("323", 2);
String obj = map.remove("123");

// use fast* methods when previous value is not required
map.fastPut("a", 1);
map.fastPutIfAbsent("d", 32);
map.fastRemove("b");

RFuture<String> putAsyncFuture = map.putAsync("321");
RFuture<Void> fastPutAsyncFuture = map.fastPutAsync("321");

RLocalCachedMap lets you configure the maximum size of the local cache, the time to live and maximum idle time per entry, the eviction policy, and how invalidation is propagated to other application instances. Because the local copy lives in the JVM heap, reads that hit it never touch the network - the reason this pattern is often called a near cache.

Redisson also plugs into the caching abstractions Java applications already use, so an existing codebase usually needs configuration rather than rewriting: Spring Boot's @Cacheable, the Hibernate second-level cache, MyBatis caching, and the JCache (JSR-107) standard API.

Common Redis caching mistakes

  • No TTL on cache entries. Memory fills, eviction begins at an arbitrary moment, and keys start disappearing under load rather than on a schedule you chose.
  • Caching everything. A cache earns its keep on the hot minority of data. Caching rarely read values costs memory and buys almost no hits.
  • Ignoring cache stampede. When a popular key expires, every concurrent request misses at once and hits the database together — the thundering herd problem. Stagger expiry times or use a lock so one request repopulates while the others wait.
  • Treating a cache as a system of record. If losing the data would be a problem, you need persistence configured and eviction disabled - at which point you are running an in-memory database, not a cache.
  • Not measuring hit rate. The keyspace_hits and keyspace_misses counters in INFO stats tell you whether the cache is working. A cache miss rate that climbs over time usually means the TTL or the eviction policy needs revisiting.

For caches spanning multiple application instances or data centers, see distributed caching.

Redis cache FAQ

What is a Redis cache used for? Most often for database query results, user sessions, API responses from slow upstream services, and computed values such as leaderboards or counters. Anything expensive to produce and read far more often than it changes is a candidate.

Is Redis a database or a cache? It can be either. Used as a cache it holds a disposable copy of data owned elsewhere; used as a database it is the system of record and needs persistence configured and eviction disabled. See in-memory database for what changes when it holds the truth.

Why is Redis faster than a relational database? It serves reads from RAM rather than disk, which is roughly a thousand times faster than an SSD read, and it avoids the query planning, joins, and buffer management a relational engine performs on every request.

What is the difference between a cache and a Redis cache? A cache is the general pattern. A Redis cache is that pattern implemented on Redis or Valkey, which adds structured values, eight eviction policies, TTL per key, replication, and clustering that a simple in-process cache does not provide.

Similar terms