Lettuce

JavaCache LibraryRedisAsynchronousReactiveNoSQL

GitHub Overview

redis/lettuce

Advanced Java Redis client for thread-safe sync, async, and reactive usage. Supports Cluster, Sentinel, Pipelining, and codecs.

Stars5,663
Watchers204
Forks1,056
Created:May 10, 2014
Language:Java
License:MIT License

Topics

asynchronousaws-elasticacheazure-redis-cachejavareactiveredisredis-clientredis-clusterredis-sentinel

Star History

redis/lettuce Star History
Data as of: 10/22/2025, 10:05 AM

Cache Library

Lettuce

Overview

Lettuce is an advanced Redis client library for Java applications.

Details

Lettuce is an officially supported Java Redis client that joined Redis' official client family in 2024, provided as open source under the MIT license. It features thread-safe design allowing multiple threads to safely share a single connection, supporting four programming models: synchronous, asynchronous, reactive, and Kotlin coroutines. Built on Netty's non-blocking I/O architecture, it delivers high performance and low latency while providing rich features including Redis Sentinel, Redis Cluster, pipelining, automatic reconnection, SSL/TLS, and Pub/Sub. Leveraging Java 8's CompletionStage interface, it provides fine-grained control over how applications receive data. The library supports all Redis commands and deployment models, making it suitable for various use cases from simple caching to complex distributed systems. Its scalable and thread-safe design eliminates the need for connection pooling in most scenarios, while its reactive API integrates seamlessly with Project Reactor for reactive programming paradigms.

Pros and Cons

Pros

  • Thread-Safe: Single connection can be safely shared across multiple threads
  • High Performance: Netty-based non-blocking I/O for high throughput
  • Rich API Models: Supports sync, async, reactive, and coroutine paradigms
  • Robust Connection Management: Automatic reconnection and command buffering
  • Complete Redis Support: Full command set and deployment model coverage
  • Official Support: Officially supported by Redis with continuous development
  • Spring Integration: Excellent integration with Spring Data Redis

Cons

  • Learning Curve: Multiple API models and advanced features require study
  • Blocking Operation Constraints: BLPOP and MULTI/EXEC need dedicated connections
  • Memory Overhead: Rich feature set may consume slightly more memory
  • Configuration Complexity: Advanced features may require complex configuration

Key Links

Code Examples

Basic Connection and Operations

import io.lettuce.core.*;

// Create Redis client
RedisClient client = RedisClient.create("redis://localhost:6379");

// Establish connection
StatefulRedisConnection<String, String> connection = client.connect();

// Get synchronous commands
RedisCommands<String, String> commands = connection.sync();

// Basic operations
commands.set("key", "Hello, Lettuce!");
String value = commands.get("key");
System.out.println(value); // "Hello, Lettuce!"

// Clean up resources
connection.close();
client.shutdown();

Asynchronous API

import io.lettuce.core.api.async.RedisAsyncCommands;
import java.util.concurrent.CompletableFuture;

RedisClient client = RedisClient.create("redis://localhost:6379");
StatefulRedisConnection<String, String> connection = client.connect();
RedisAsyncCommands<String, String> async = connection.async();

// Asynchronous SET operation
RedisFuture<String> setResult = async.set("async-key", "async-value");

// Asynchronous GET operation
RedisFuture<String> getValue = async.get("async-key");

// Handle results
setResult.thenAccept(result -> System.out.println("SET result: " + result));
getValue.thenAccept(value -> System.out.println("GET result: " + value));

// Execute multiple operations concurrently
List<RedisFuture<String>> futures = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    futures.add(async.set("key-" + i, "value-" + i));
}

// Wait for all operations to complete
LettuceFutures.awaitAll(1, TimeUnit.MINUTES, 
    futures.toArray(new RedisFuture[0]));

Reactive API

import io.lettuce.core.api.reactive.RedisReactiveCommands;
import reactor.core.publisher.Mono;

RedisClient client = RedisClient.create("redis://localhost:6379");
StatefulRedisConnection<String, String> connection = client.connect();
RedisReactiveCommands<String, String> reactive = connection.reactive();

// Reactive streams
Mono<String> setMono = reactive.set("reactive-key", "reactive-value");
Mono<String> getMono = reactive.get("reactive-key");

// Chain operations
setMono
    .then(getMono)
    .doOnNext(value -> System.out.println("Value: " + value))
    .subscribe();

// Process multiple values
reactive.mget("key1", "key2", "key3")
    .flatMapIterable(values -> values)
    .filter(value -> value.hasValue())
    .map(value -> value.getValue())
    .doOnNext(System.out::println)
    .subscribe();

Redis Cluster Connection

import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;

// Configure cluster nodes
RedisURI node1 = RedisURI.create("redis://localhost:7000");
RedisURI node2 = RedisURI.create("redis://localhost:7001");
RedisURI node3 = RedisURI.create("redis://localhost:7002");

// Create cluster client
RedisClusterClient clusterClient = RedisClusterClient
    .create(Arrays.asList(node1, node2, node3));

// Connect to cluster
StatefulRedisClusterConnection<String, String> connection = 
    clusterClient.connect();

RedisAdvancedClusterCommands<String, String> commands = 
    connection.sync();

// Cluster operations
commands.set("cluster-key", "cluster-value");
String value = commands.get("cluster-key");

// Configure read preference (read from replica)
connection.setReadFrom(ReadFrom.REPLICA);

connection.close();
clusterClient.shutdown();

SSL/TLS Connection

// SSL/TLS connection configuration
RedisURI redisUri = RedisURI.Builder.redis("secure.redis.com")
    .withPort(6380)
    .withSsl(true)
    .withPassword("secure-password")
    .withDatabase(0)
    .build();

RedisClient client = RedisClient.create(redisUri);
StatefulRedisConnection<String, String> connection = client.connect();

// Execute commands over SSL
RedisCommands<String, String> commands = connection.sync();
commands.set("secure-key", "secure-value");

Pub/Sub Functionality

import io.lettuce.core.pubsub.RedisPubSubListener;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;

// Pub/Sub connection
StatefulRedisPubSubConnection<String, String> pubsubConnection = 
    client.connectPubSub();

// Configure listener
pubsubConnection.addListener(new RedisPubSubListener<String, String>() {
    @Override
    public void message(String channel, String message) {
        System.out.println("Received: " + message + " from " + channel);
    }

    @Override
    public void subscribed(String channel, long count) {
        System.out.println("Subscribed to " + channel);
    }

    @Override
    public void unsubscribed(String channel, long count) {
        System.out.println("Unsubscribed from " + channel);
    }
});

// Subscribe to channels
RedisPubSubCommands<String, String> pubsub = pubsubConnection.sync();
pubsub.subscribe("news", "updates");

// Publish message (from separate connection)
RedisCommands<String, String> publisher = client.connect().sync();
publisher.publish("news", "Breaking news!");