Home / Code Samples / Java
Verdict: Lettuce for Redis in new Spring Boot apps. Jedis if you want the simpler thread-per-call model. Redisson if you want high-level distributed primitives. XMemcached or spymemcached for Memcached.

Java Clients for Redis vs Memcached

The JVM has the deepest Redis client ecosystem of any language: three excellent clients (Lettuce, Jedis, Redisson) each with different strengths. The Memcached side has two viable clients. Spring Boot's defaults steer most new Java work toward Lettuce.

Lettuce
Spring Boot default
Netty-based, sync + async + reactive
Jedis
Simpler sync client
Per-thread or pool-based
Redisson
Distributed objects
RLock, RMap, RList over Redis
spymemcached
Memcached default
Plus XMemcached as alternative

Lettuce: the modern default

Lettuce is built on Netty and provides three API styles in one client: synchronous (for traditional blocking code), asynchronous (CompletionStage-based for futures-style concurrency), and reactive (Project Reactor Flux and Mono for backpressure-aware streaming). One Lettuce client instance is thread-safe and is intended to be shared across the entire application, with internal connection multiplexing.

Spring Boot's spring-boot-starter-data-redis depends on Lettuce by default since Spring Boot 2.0 (2018). Switching to Jedis requires an explicit dependency exclusion and adding the Jedis dependency. For most Spring Boot apps the default works well: you get sync Redis operations via RedisTemplate, async via ReactiveRedisTemplate (in the reactive Spring Web stack), and automatic connection management.

Cluster support is built in: RedisClusterClient.create(uris) gives you a cluster-aware client that handles topology discovery, MOVED redirections, and node failover automatically. Pub/sub is supported with dedicated connections (you do not subscribe on the shared command connection). Pipeline batching is supported via connection.setAutoFlushCommands(false) then explicit flush after batching.

Side-by-side: a rate limiter

Lettuce (Spring Boot)
@Service
public class RateLimiter {
  @Autowired
  private StringRedisTemplate redis;

  public boolean allow(String user, int limit, int winSec) {
    String key = "rl:" + user + ":" +
                  (System.currentTimeMillis()/1000/winSec);
    Long count = redis.opsForValue().increment(key);
    redis.expire(key, Duration.ofSeconds(winSec));
    return count <= limit;
  }
}

// Single bean, shared across all controllers.
// Lettuce multiplexes the underlying connection.
spymemcached
@Service
public class RateLimiter {
  private final MemcachedClient mc;

  public RateLimiter() throws IOException {
    mc = new MemcachedClient(
      new InetSocketAddress("localhost", 11211));
  }

  public boolean allow(String user, int limit, int winSec) {
    String key = "rl:" + user + ":" +
                  (System.currentTimeMillis()/1000/winSec);
    // Add first (races against another worker)
    mc.add(key, winSec, "0");
    long count = mc.incr(key, 1, 1L, winSec);
    return count <= limit;
  }
}

// Add+incr is two round trips per call.
// Race recoverable but fragile.

Jedis: the simpler choice

Jedis is the older Redis client for Java, now maintained by Redis Inc. It is intentionally simpler than Lettuce: a Jedis instance represents one connection, is not thread-safe, and is meant to be used either per-thread or pooled via JedisPool. The mental model is closer to JDBC connection pooling than to Lettuce's multiplexed-client model.

For applications with simple sync access patterns, Jedis can be easier to reason about: one connection, one operation, no surprises about which thread is handling the I/O. The downside is the connection pool maintenance and the inability to share a single client across many threads. For high-concurrency workloads Lettuce's multiplexing wins on both efficiency and operational simplicity.

Jedis remains the right choice when you specifically want explicit connection control (e.g. for transaction isolation requirements that don't match Lettuce's auto-flushing model), when you're working with older Spring Boot 1.x or non-Spring frameworks where Lettuce integration is less mature, or when you have existing Jedis-based code and the migration cost to Lettuce is not justified.

Redisson: distributed objects, Redlock, and more

Redisson is a different category of Redis client. Instead of exposing raw Redis commands, it provides distributed-Java-object abstractions: RMap<K,V> behaves like a ConcurrentHashMap but backed by Redis, RLock implements Java's Lock interface but the lock is distributed across all JVMs talking to the same Redis. Built-in support for Redlock multi-node distributed locking.

Redisson is the right choice when you want to use Redis as a coordination primitive without thinking about Redis commands. If your code path is "I want a distributed map" or "I want a leader election," Redisson hides the Redis-specific implementation and gives you a familiar Java API. The trade-off is some performance overhead and a learning curve for the Redisson-specific API; the gain is cleaner application code that does not have command-level Redis logic interleaved.

For pure Redis command access in performance-critical paths, drop down to Lettuce or Jedis. For high-level coordination (locks, leader election, counters, queues as Java objects), Redisson is faster to write and easier to maintain. Many production systems use both: Redisson for the distributed-primitives layer, Lettuce for the per-request raw cache operations.

FAQ

Lettuce or Jedis?

Lettuce for new code. It is the default Redis client in Spring Boot since 2.0, supports reactive (Project Reactor) and async APIs in addition to sync, uses Netty for non-blocking I/O, and one Lettuce client instance is thread-safe and intended to be shared across the application. Jedis is older, requires per-thread instances or a connection pool, and lacks the reactive API.

What does Redisson add?

Higher-level distributed primitives: distributed locks (RLock implementing Java's Lock interface), distributed collections (RMap, RList, RSet), distributed services, and built-in Redlock. Convenient when you want to use Redis as a coordination primitive without dropping to raw commands. Built on top of Netty, similar performance profile to Lettuce.

spymemcached or XMemcached?

Both are still maintained. spymemcached is the older library, simpler API, widely used in legacy code. XMemcached is more modern, supports more advanced features like binary protocol auth and the latest Memcached commands. For new code XMemcached is the slightly better default; for compatibility with existing Java caches, spymemcached is fine.

Spring Cache abstraction?

Spring's @Cacheable annotation works with both Redis and Memcached via cache-abstraction adapters. spring-boot-starter-data-redis uses Lettuce by default. For Memcached, spring-context-support has a SimpleCacheManager backed by a Memcached-specific CacheManager (community-maintained, less integrated than the Redis story).

Connection pool sizing?

Lettuce: one client instance handles arbitrary concurrency over a single multiplexed connection (or one per cluster node), no pool needed. Jedis: use JedisPool with maxTotal sized to your max-concurrent-Redis-operations (usually 16-32 for typical web apps). For spymemcached, the library handles connection multiplexing internally; one client per JVM is sufficient.

Related decisions

Go clients
go-redis, gomemcache
.NET clients
StackExchange.Redis
Distributed locks
Redisson Redlock
All code samples
Hub