Spring Boot works with Redis out of the box — just add the dependency, point it at an address, and pick the tool you need: manual operations through RedisTemplate, automatic caching through @Cacheable, or session storage through Spring Session.
Connecting and the Lettuce client
By default, Spring Data Redis uses the Lettuce client — asynchronous, thread-safe, built on Netty. Add the dependency:
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
Configure it in application.yml:
spring:
data:
redis:
host: localhost
port: 6379
# password: secret # if authentication is enabled
# database: 0 # logical database number (0 by default)
lettuce:
pool:
max-active: 8
max-idle: 4
Spring Boot automatically creates a LettuceConnectionFactory and a RedisTemplate<String, Object>. You only need to override the connection bean for non-standard configurations (cluster, Sentinel, TLS).
RedisTemplate and StringRedisTemplate
RedisTemplate is a general-purpose tool for direct operations with Redis. It exposes "operations" grouped by data structure type:
@Service
public class CounterService {
private final StringRedisTemplate redis;
public CounterService(StringRedisTemplate redis) {
this.redis = redis;
}
public void increment(String key) {
redis.opsForValue().increment(key);
redis.expire(key, Duration.ofHours(1));
}
public Long get(String key) {
String value = redis.opsForValue().get(key);
return value != null ? Long.parseLong(value) : 0L;
}
}
StringRedisTemplate is a RedisTemplate<String, String> with string serialization. It fits when both the key and the value are strings.
Operations by structure type:
| Method | Redis data type |
|---|---|
opsForValue() | String (scalar value) |
opsForHash() | Hash |
opsForList() | List |
opsForSet() | Set |
opsForZSet() | Sorted Set |
Gotcha: default serialization
If you use RedisTemplate<String, Object> without configuring it, values are stored via JdkSerializationRedisSerializer. The data in Redis looks like an unreadable byte stream and is tied to specific Java classes — if the class changes, deserialization breaks.
The right approach is to configure JSON serialization:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
ObjectMapper mapper = new ObjectMapper();
mapper.activateDefaultTyping(
mapper.getPolymorphicTypeValidator(),
ObjectMapper.DefaultTyping.NON_FINAL
);
Jackson2JsonRedisSerializer<Object> serializer =
new Jackson2JsonRedisSerializer<>(mapper, Object.class);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
return template;
}
}
After this, values in Redis are stored as readable JSON.
Spring Cache on top of Redis
Spring Cache is an abstraction over a cache. You decorate a method with an annotation, and Spring decides for you: go to the database or return the cached result.
Dependency and enabling
implementation 'org.springframework.boot:spring-boot-starter-cache'
@SpringBootApplication
@EnableCaching
public class Application { ... }
@Cacheable, @CacheEvict, @CachePut
@Service
public class ProductService {
@Cacheable(value = "products", key = "#id")
public Product findById(Long id) {
// called only on a cache miss
return repository.findById(id).orElseThrow();
}
@CacheEvict(value = "products", key = "#product.id")
public void update(Product product) {
repository.save(product);
// the cache entry for this key is evicted
}
@CachePut(value = "products", key = "#result.id")
public Product create(Product product) {
return repository.save(product);
// the method always runs, the result is written to the cache
}
@CacheEvict(value = "products", allEntries = true)
public void invalidateAll() {
// clear the entire products cache
}
}
RedisCacheManager and TTL
By default the cache lives forever. You can set a TTL through RedisCacheManager:
@Configuration
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration defaults = RedisCacheConfiguration
.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.serializeValuesWith(
RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer())
);
Map<String, RedisCacheConfiguration> cacheConfigs = Map.of(
"products", defaults.entryTtl(Duration.ofHours(1)),
"sessions", defaults.entryTtl(Duration.ofMinutes(5))
);
return RedisCacheManager.builder(factory)
.cacheDefaults(defaults)
.withInitialCacheConfigurations(cacheConfigs)
.build();
}
}
Short formula: RedisCacheConfiguration is the setup for a single cache; RedisCacheManager assembles them together and registers them with Spring.
Sessions with Spring Session
Spring Session moves user HTTP sessions out of the application's memory and into Redis. This gives you two things:
- Horizontal scaling — several application instances share a common session store, so the user doesn't lose their session when switching between them.
- Surviving restarts — sessions don't disappear when the application restarts.
Dependency:
implementation 'org.springframework.session:spring-session-data-redis'
In application.yml:
spring:
session:
store-type: redis
timeout: 30m
redis:
flush-mode: on-save # write the session only when it changes
namespace: "myapp:session"
Nothing else needs configuring — Spring Boot automatically creates a RedisIndexedSessionRepository and wires in the SessionRepositoryFilter. Existing code that uses HttpSession works without changes.
What it looks like in Redis
After running the application with @Cacheable and Spring Session, the keys in Redis will look roughly like this:
# Cache via @Cacheable
> KEYS products::*
1) "products::42"
2) "products::17"
> GET "products::42"
"{\"id\":42,\"name\":\"Widget\",\"price\":9.99}"
> TTL "products::42"
(integer) 3542 # seconds until expiry
# Sessions via Spring Session
> KEYS myapp:session:*
1) "myapp:session:sessions:a3f9c..."
2) "myapp:session:sessions:b12ef..."
In short
- Lettuce is the default client in Spring Boot; thread-safe, configured in
application.yml. StringRedisTemplateis for string operations;RedisTemplate<String, Object>is for complex values.- Changing serialization is mandatory: replace
JdkSerializationRedisSerializerwithGenericJackson2JsonRedisSerializer. @Cacheable/@CacheEvict/@CachePutprovide declarative caching;@EnableCachingturns the mechanism on.RedisCacheManagerconfigures TTL separately for each cache.- Spring Session moves HTTP sessions into Redis — scaling without losing sessions.
Further reading
- Redis fundamentals — data structures, TTL, persistence
- Caching patterns — cache-aside, read-through, write-through, and when to use each
- Operating Redis — monitoring, replication, Sentinel