How to Use Redis (or Valkey) in Java: A Complete Guide with Code Examples
Redis is one of the most widely used in-memory data stores, and Java is one of the most widely used languages to build the services that rely on it. The catch: Java can't talk to Redis on its own. Redis speaks its own wire protocol over a TCP socket, so you need a client library to bridge the two.
This guide walks you through everything you need to go from an empty project to a running Java application backed by Redis (or Valkey, the open-source fork that speaks the same protocol). We'll use Redisson, a high-level Redis and Valkey client that exposes familiar Java types, like Map, List, and Lock, backed by the server instead of local memory.
By the end you'll have working code for the core data structures and a clear map of where to go next for clustering, caching, locking, and production hardening.
Which Redis Client Should You Use in Java?
There are three clients most Java teams consider, and they sit at different levels of abstraction:
- Jedis — a thin, synchronous wrapper around Redis commands. You send commands, you parse replies. Simple, but you build everything above it yourself.
- Lettuce — a lower-level client too, with strong asynchronous and reactive support built on Netty.
-
Redisson — a higher-level client. Instead of raw commands, you work with distributed implementations of standard Java interfaces (
Map,Set,Queue,Lock,AtomicLong) plus services like caching, pub/sub, and rate limiting.
If you want raw command access, Jedis or Lettuce are fine. If you'd rather write ordinary Java and let the library handle the distributed plumbing, Redisson is the faster path, and it's what this guide uses. For a side-by-side breakdown, see Redisson vs Jedis, Redisson vs Lettuce, and Redisson vs Spring Data Redis.
Prerequisites
Before you start, make sure you have:
-
JDK 8 or later installed (
java -version). - Maven or Gradle for dependency management.
- A running Redis or Valkey server. For local development you can run one in seconds. If you don't have one yet, follow How to install Redis, or start a container:
# Redis
docker run -d --name redis -p 6379:6379 redis
# ...or Valkey (same protocol, same code)
docker run -d --name valkey -p 6379:6379 valkey/valkey
Confirm it responds:
redis-cli ping
# PONG
Everything below works identically against Valkey, since Valkey is wire-compatible with Redis. If you're weighing the two, see Valkey vs Redis: A Comparison.
Step 1 — Add the Redisson Dependency
Add Redisson to your build. Use the latest release from Maven Central — 4.6.1 at the time of writing. Redisson 4.x runs on JDK 8 and later and supports Redis 3.0+ and Valkey 7.2.5+.
Maven (pom.xml):
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>4.6.1</version>
</dependency>
Gradle (build.gradle):
implementation 'org.redisson:redisson:4.6.1'
Step 2 — Connect to Redis or Valkey
Redisson is configured through a Config object and started with Redisson.create(). The most common setup, a single server, looks like this:
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class Application {
public static void main(String[] args) {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
// ... use the client ...
redisson.shutdown();
}
}
A few things worth knowing:
- The
redis://scheme is used for both Redis and Valkey. For a TLS connection, userediss://(see the note on production below). - If your server requires authentication, add
.setPassword("your-password")to theuseSingleServer()builder. -
RedissonClientis thread-safe and manages its own connection pool. Create one instance per application and reuse it, don't build a new client per request.
That single-server config is one of several topologies. Redisson also supports Redis Cluster, Sentinel, replicated, and managed cloud deployments, and the only thing that changes is the config block. See the configuration docs for the full list.
Step 3 — Your First Operations
With a client in hand, the simplest thing you can store is a single object. Redisson calls this an RBucket:
import org.redisson.api.RBucket;
RBucket<String> bucket = redisson.getBucket("greeting");
bucket.set("Hello from Redisson");
String value = bucket.get();
System.out.println(value); // Hello from Redisson
The other structure you'll reach for constantly is a map. RMap implements java.util.concurrent.ConcurrentMap, so it behaves like a Map you already know, except the data lives on the server and is visible to every instance of your application:
import org.redisson.api.RMap;
RMap<String, String> map = redisson.getMap("user:1001");
map.put("name", "Ada");
map.put("role", "engineer");
String name = map.get("name"); // Ada
boolean isEngineer = map.containsKey("role");
Under the hood an RMap is stored as a Redis hash; Redisson just gives you the Java Map API on top of it.
Step 4 — Common Data Structures
Redisson maps most of the standard Java collections onto Redis data types. Here are the ones you'll use most often.
Lists — an ordered, index-addressable collection (RList implements java.util.List):
import org.redisson.api.RList;
RList<String> list = redisson.getList("tasks");
list.add("compile");
list.add("test");
list.add("deploy");
System.out.println(list.size()); // 3
System.out.println(list.get(0)); // compile
Sets — unique elements, no duplicates (RSet implements java.util.Set):
import org.redisson.api.RSet;
RSet<String> tags = redisson.getSet("post:42:tags");
tags.add("redis");
tags.add("java");
tags.add("redis"); // ignored, already present
Queues — FIFO access, useful for lightweight job passing (RQueue implements java.util.Queue):
import org.redisson.api.RQueue;
RQueue<String> queue = redisson.getQueue("jobs");
queue.add("job-1");
String next = queue.poll(); // job-1
Atomic counters — a distributed AtomicLong, safe to increment from many machines at once:
import org.redisson.api.RAtomicLong;
RAtomicLong counter = redisson.getAtomicLong("page:views");
counter.incrementAndGet();
counter.addAndGet(10);
long total = counter.get();
These are the everyday building blocks. For a deeper tour of the most useful objects and when to reach for each, see The Top 5 Redis-Based Java Objects. If you need to store structured records rather than flat values, storing JSON with Redis on Java covers that pattern.
Step 5 — Beyond the Basics
Once the collections feel natural, Redisson's higher-level services are where it pulls ahead of a raw command client. A few you'll likely want:
-
Distributed locks. An
RLockimplementsjava.util.concurrent.locks.Lockbut coordinates across every node in your system, so only one instance runs a critical section at a time:
Full patterns, including lease times and fair locks, are in How to Use Redis Locks in Java.import org.redisson.api.RLock; RLock lock = redisson.getLock("order:1001"); lock.lock(); try { // only one node executes this at a time } finally { lock.unlock(); } - Caching. Redisson can back a read-through/write-through cache so hot data stays close to your application. See How to Use Redis Cache in Java.
- Publish/subscribe messaging. Decouple producers and consumers with topics: How to Use Redis Pub/Sub in Java.
- Rate limiting. Throttle traffic across a fleet with a distributed limiter: Distributed Rate Limiting in Java with Spring Boot.
- Streams. For append-only logs and event processing, see Redis Streams for Java.
Redisson also offers synchronous, asynchronous, reactive, and RxJava APIs for nearly every object, so you can match it to whatever concurrency model your service already uses.
Build and Run the App
Putting it together, here's a complete, runnable example:
import org.redisson.Redisson;
import org.redisson.api.RBucket;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class Application {
public static void main(String[] args) {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
RBucket<String> bucket = redisson.getBucket("greeting");
bucket.set("Hello from Redisson");
System.out.println("bucket: " + bucket.get());
RMap<String, String> map = redisson.getMap("user:1001");
map.put("name", "Ada");
System.out.println("map: " + map.get("name"));
redisson.shutdown();
}
}
Save this as src/main/java/Application.java, in a project whose pom.xml contains the Redisson dependency from Step 1. Then compile and run it with Maven:
mvn compile
mvn exec:java -Dexec.mainClass=Application
You should see the stored values printed back. That's a working Redis-backed Java application.
Production Notes
The single-server setup above is perfect for local development. Before you ship, a few things change:
-
Security. Redis and Valkey ship with no authentication by default, which is dangerous if the port is reachable. Require a password (
.setPassword(...)) and use TLS with therediss://scheme. Never expose the server directly to the internet. - High availability. Production usually means a cluster or Sentinel topology rather than a single node. Redisson handles failover and node discovery for you once configured.
- Managed services. If you run on a cloud provider, Redisson connects to the managed offerings directly, for example AWS ElastiCache, Azure Cache, Google Cloud Memorystore, and Amazon MemoryDB.
-
Connection reuse. As noted, keep one
RedissonClientfor the lifetime of the app.
For workloads that need local (near) caching, data partitioning, or advanced cache strategies, Redisson PRO adds those on top of the same API. You can try it for free.
Frequently Asked Questions
Can Java Connect to Redis Directly?
No. Redis has no native Java API, so you need a client library, such as Redisson, Jedis, or Lettuce, that speaks the Redis protocol over the network.
What Is the Best Redis Client for Java?
It depends on the abstraction you want. Jedis and Lettuce give you low-level command access; Redisson gives you distributed versions of standard Java types plus higher-level services like locks, caching, and rate limiting. Teams that prefer writing ordinary Java tend to choose Redisson.
Does Redisson Work With Valkey?
Yes. Valkey is wire-compatible with Redis, so the same configuration, addresses, and code shown here work against Valkey without changes.
How Do I Connect to a Redis Cluster in Java?
Swap the single-server config for useClusterServers() and add your node addresses. See How to Connect to Redis Cluster in Java for the full setup.
Do I Need to Create a New Client for Every Request?
No. RedissonClient is thread-safe and pools connections internally. Create one instance at startup, share it across your application, and shut it down when the app stops.
Next Steps
You now have a Redis- or Valkey-backed Java app and the core data structures to build on. From here, pick the capability your use case needs, locks, caching, pub/sub, or clustering, and go deeper. The full Redisson documentation covers every object and service in detail.