redis/lettuce: the thread-safe Java Redis client with sync, async and reactive APIs
Advanced Java Redis client for thread-safe sync, async, and reactive usage. Supports Cluster, Sentinel, Pipelining, and codecs.
At a glance
- What is it?
- Lettuce is a Netty-based Java client for Redis that lets many threads share one connection, with synchronous, asynchronous and reactive command interfaces plus Cluster, Sentinel and codec support. It is a strong fit for JVM services that already live in a reactive or async stack, and a poor fit if you need blocking commands on a shared connection.
- Who is it for?
- Adopt Lettuce if you are building a JVM service on Netty, Reactor or a similar async stack and want one shared connection across threads. Do not adopt it if your workload is dominated by blocking commands such as BLPOP or MULTI/EXEC on a shared connection, since the README states threads must avoid those.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What Lettuce solves for JVM services talking to Redis
Most Java Redis clients make you choose between a simple blocking API and a connection pool that has to be sized and monitored. Lettuce takes a different position: a single connection is thread-safe, so multiple threads may share it provided they avoid blocking and transactional operations such as BLPOP and MULTI/EXEC. That constraint is stated plainly in the README, and it shapes everything else about the library.
The audience is narrower than "anyone using Redis from Java". Lettuce is built on Netty, and it exposes three command interfaces over the same connection: synchronous, asynchronous and reactive. A team already running a Reactor-based service gets a client whose reactive API matches the rest of the stack. A team with a plain servlet application that mostly wants get and set can use the synchronous interface, but the asynchronous and reactive surfaces are where the project's design pays off.
One connection, three command interfaces, and where the sharing stops
The mechanism is straightforward to describe from the README. You create a RedisClient from a Redis URI, call connect() to obtain a StatefulRedisConnection, and then pick a view of that connection: connection.sync(), connection.async() or connection.reactive(). All three return command objects backed by the same connection.
Command naming follows Redis itself. Each Redis command is implemented by one or more methods whose names are the lowercase Redis command name. Commands with modifiers that change the result type fold the modifier into the method name in CamelCase, so zrangebyscore and zrangebyscoreWithScores are separate methods. If you know the Redis command, you can usually guess the Java method.
The thread-safety claim comes with the blocking caveat, and that is the real design boundary. A shared connection works because non-blocking commands are multiplexed over it. Once a command blocks the connection, other threads waiting on the same connection are stuck behind it. The README does not describe a fallback for that case, so the practical answer is to keep blocking and transactional work off the shared connection rather than expect the client to sort it out.
Installing lettuce-core from Maven Central
The README points to Maven Central for binaries and dependency information. The Maven coordinates are io.lettuce:lettuce-core, and the README shows the dependency block with a placeholder version, so you choose the release yourself. The most recent release listed in the repository is 7.7.0.RELEASE, published on 2026-08-18.
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>x.y.z</version>
</dependency>Replace x.y.z with the release you want. The README also documents a snapshot repository at https://oss.sonatype.org/content/repositories/snapshots/ with a version suffix of BUILD-SNAPSHOT, but snapshot builds are for tracking the upcoming major version, not for production pinning.
The README states compatibility with Java 8 and later, describing the artifact as an implicit automatic module without descriptors. That matters if you are on the module path: there is no module-info to declare requires on, so you depend on the automatic module name derived from the jar.
A first connection and a first command
The README's basic usage example is the shortest path to a working call. RedisClient.create takes a Redis URI, connect() returns a StatefulRedisConnection, and connection.sync() gives you the blocking command interface.
RedisClient client = RedisClient.create("redis://localhost");
StatefulRedisConnection<String, String> connection = client.connect();
RedisStringCommands sync = connection.sync();
String value = sync.get("key");After this code runs, value holds whatever is stored at "key", or null if the key does not exist. The URI scheme selects the connection type; the README uses redis://localhost, which points at a local server on the default port.
The asynchronous interface returns futures instead of values, and the README shows awaiting several of them together with LettuceFutures.awaitAll. The reactive interface returns Reactor types, with set.subscribe() to trigger execution and get.block() to obtain the value. All three examples in the README assume the same connection object, which is the point of the design.
Where Lettuce is the wrong tool
The blocking constraint is the first limitation, and it is not a footnote. If your application's hot path is a blocking pop from a queue, or a transaction that spans MULTI and EXEC on a shared connection, the README's own guidance says other threads must avoid those operations. You either keep those commands on a dedicated connection or you accept that the shared model does not apply to that part of your workload.
The second limitation is documentation depth in the repository itself. The README is a signpost: it lists features and links out to the reference documentation, the Javadoc and the wiki. It does not explain how Sentinel failover is detected, how Cluster slot routing is refreshed, or what the auto-reconnect strategy does in each failure case. Those answers live in the linked pages, and anyone evaluating Lettuce from the README alone will come away with a feature list rather than an operational picture.
The third is Java version reach. The README says Java 8 and later, and the artifact has no module descriptor. Projects that require explicit JPMS modules, or that want a client whose API surface is trimmed to a single modern style, will find the three-interface design broader than they need.
How Lettuce differs from a blocking, pool-per-thread client
The natural comparison is with a client that hands each thread its own connection from a pool and blocks on every call. That model is simpler to reason about: a blocking call occupies one pooled connection, so concurrency is bounded by pool size and there is no shared-connection caveat to remember.
Lettuce inverts the trade. One connection serves many threads, and the asynchronous and reactive interfaces let a caller issue commands without occupying a thread while waiting. The cost is that the caller has to understand which operations are safe to share. In a pool-per-thread client, BLPOP on one connection is a local decision. In Lettuce, the same call on the shared connection is a decision that affects every other thread using it.
That difference is the whole evaluation. If your service is built around futures or reactive streams and wants to minimize connections, Lettuce's model fits. If your service is a straightforward request-per-thread application with blocking calls throughout, the shared-connection advantage is mostly unused, and the constraint is pure overhead.
Maintenance, releases and licence
The repository is not archived, and the last push was on 2026-08-18, the same date as the 7.7.0.RELEASE release. Two earlier releases in the same year, 7.6.0.RELEASE on 2026-05-28 and 7.5.2.RELEASE on 2026-05-15, show a release cadence measured in months rather than years.
Upgrade cost is mostly a version bump in your build file, but the release notes file in the repository root is where breaking changes would be recorded, and the README does not summarize them. Pin an explicit version rather than relying on a range, and read RELEASE-NOTES.md before moving between minor versions.
Building Lettuce from source is a different exercise from consuming it. The repository has a Makefile with targets start, test, stop and clean, and the README says tests require multiple running Redis instances configured through that Makefile. The Makefile defines SUPPORTED_TEST_ENV_VERSIONS spanning 7.2 through 8.10, with 8.10 as the default, and drives them through docker compose files under src/test/resources/docker-env. That is contributor tooling, not something an application needs.
The licence is MIT, stated in the README and in the LICENSE file. MIT is permissive, so redistributing the library inside a product is normally straightforward, but the repository also notes it is a fork of https://github.com/wg/lettuce, so the provenance of the copyright notices is worth a look if your process requires it. This is not legal advice.
Editorial conclusion
Adopt Lettuce if you are building a JVM service on Netty, Reactor or a similar async stack and want one shared connection across threads. Do not adopt it if your workload is dominated by blocking commands such as BLPOP or MULTI/EXEC on a shared connection, since the README states threads must avoid those. Before committing, verify the lettuce-core version you pin against your Java runtime, and read the reference documentation for your exact Redis topology (standalone, Sentinel or Cluster) because the README only links to it rather than describing it.
Frequently asked questions
How do I install redis/lettuce in a Java project?
Add the io.lettuce:lettuce-core dependency from Maven Central, using the version you want in place of the placeholder in the README's Maven example. The README points to Maven Central for binaries and dependency information for Maven, Ivy, Gradle and others.
How do I use redis/lettuce to connect to Redis?
The README's basic usage creates a RedisClient with RedisClient.create("redis://localhost"), calls connect() for a StatefulRedisConnection, and then uses connection.sync(), connection.async() or connection.reactive() depending on the API you want.
Which Redis features does redis/lettuce support?
The README lists synchronous, asynchronous and reactive usage, Redis Sentinel, Redis Cluster, SSL and Unix Domain Socket connections, a streaming API, codecs, multiple command interfaces, native transports, and support for RediSearch, RedisJSON and Redis Vector Sets.
Can multiple threads share one redis/lettuce connection?
Yes, the README describes Lettuce as thread-safe and says multiple threads may share one connection if they avoid blocking and transactional operations such as BLPOP and MULTI/EXEC.
What Java versions does redis/lettuce support?
The README states compatibility with Java 8 and later and describes the artifact as an implicit automatic module without descriptors.
What licence is redis/lettuce released under?
The README and the LICENSE file state that the repository is licensed under the MIT licence, and the README notes the project is a fork of https://github.com/wg/lettuce.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/redis-lettuce)
Community notes