Enable Redis Caching in Spring Boot: Quick Performance Win
Add Redis caching to a Spring Boot REST API in 10 minutes and make repeated reads 10x faster. Annotations, TTLs and cache invalidation explained.
▶ Watch this tutorial on MasterLabSystems on YouTube — and subscribe for more.
Introduction
If your API hits the database on every request, the cheapest performance win you can ship today is Redis caching. With three annotations and a Docker container, you can turn a 200 ms endpoint into a 5 ms endpoint.
This quick-start gets you from zero to a working cache in 10 minutes, with the patterns you actually need in production.
Who this is for
Spring Boot developers with a working REST API and at least one read-heavy endpoint that's slow.
Step 1 — Start Redis
docker run -d --name redis -p 6379:6379 redis:7-alpine
That's it. No config file, no cluster — single-node Redis is fine for caching.
Step 2 — Add the starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
Step 3 — Configure connection and TTL
spring:
data.redis:
host: localhost
port: 6379
cache:
type: redis
redis:
time-to-live: 600000
cache-null-values: false
@SpringBootApplication
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Step 4 — Cache a method
```java
@Service
public class ProductService {@Cacheable(value = "products", key = "#id") public Product findById(Long id) { return repository.findById(id).orElseThrow(); }
@CachePut(value = "products", key = "#product.id") public Product update(Product product) { return repository.save(product); }
@CacheEvict(value = "products", key = "#id") public void delete(Long id) { repository.deleteById(id); } } ```
That's the whole cache.
@Cacheable— check Redis first, only call the DB on a miss.@CachePut— always run the method, then overwrite the cache.@CacheEvict— remove the entry so the next read misses.
Step 5 — Measure it
Hit the endpoint twice with curl -w "%{time_total}\n". The first call goes to Postgres. The second call returns from Redis in single-digit milliseconds.
Pick the right TTL
A cache without a TTL is a memory leak with extra steps. Some rules of thumb:
- Reference data (product catalog, country list) — 1 hour to 1 day.
- User profile / settings — 5 to 15 minutes.
- Search results — 30 to 60 seconds.
- Anything you mutate often — evict on write, don't rely on TTL.
Common errors and fixes
SerializationException— your cached object isn't serializable. Either addimplements Serializableor configure a JSON serializer (recommended — it's debuggable inredis-cli).- Cache hit returns null for "missing" entries — Spring caches
nulltoo. Setcache-null-values: falseand let misses repeat the DB call. - Annotations do nothing — self-invocation.
@Cacheableis AOP, calls inside the same class bypass the proxy. Always call from a *different* bean. - Stale data after writes elsewhere — another service updated the DB but didn't evict. Either let it publish a Kafka event your service consumes to evict, or use a shorter TTL.
Configure JSON serialization (recommended)
@Bean
public RedisCacheConfiguration cacheConfig(ObjectMapper mapper) {
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
.disableCachingNullValues()
.serializeValuesWith(SerializationPair.fromSerializer(
new GenericJackson2JsonRedisSerializer(mapper)));
}
Now redis-cli GET products::42 returns a JSON blob you can read.
Source code
GitHub repo includes the Spring Boot app, a docker-compose.yml with Redis, and a JMeter file showing 10x throughput improvement on cached endpoints.
Related tutorials
- [Spring Boot + Redis Caching: 10x Faster APIs](/blog/spring-boot-redis-caching)
- [Spring Data JPA Best Practices](/blog/spring-data-jpa-best-practices)
- [API Rate Limiting in Spring Boot](/blog/api-rate-limiting-in-spring-boot)
<!-- AFFILIATE-SECTIONS-V1 -->
Tools used in this tutorial
The setup below uses the following tools. Versions matter less than the role each one plays, so swap freely as long as you keep the responsibilities the same.
- Redis
- Caching
- Spring Boot
- Performance
- Java 17+
- Maven / Gradle
- Docker
Real-world production context
In production, a Spring Boot service almost never runs as a single JAR on a developer laptop. It is packaged as a container image, deployed on a managed platform, and fronted by a load balancer that handles TLS, health checks and autoscaling. Database connections go through a pool sized for the instance type; secrets are injected from a managed secret store rather than checked into Git; logs and metrics stream to a central backend so on-call engineers can answer "is the system healthy?" in seconds. This is why most teams pair Spring Boot with a cloud platform from day one — the JVM is great, but the operational surface around it is what keeps the service alive.
Recommended tools & deployment options
Once the tutorial works on your machine, the next question is *where do I run this for real?* These are the platforms most backend teams reach for, and the trade-offs between them:
- [DigitalOcean](https://www.digitalocean.com/) — the simplest path from a working container to a public URL. App Platform deploys directly from a Dockerfile, managed databases and Redis are one click away, and pricing is predictable. A common way to deploy the setup in this tutorial is using a cloud provider like DigitalOcean when you want to ship quickly without learning a full cloud SDK.
- [AWS](https://aws.amazon.com/) — the default for enterprise workloads. ECS Fargate or EKS run containers without you managing servers, RDS handles the database, and CloudWatch covers logs and metrics. In production environments, developers typically host this on AWS or a similar cloud platform when they need fine-grained IAM, multi-region failover, or deep integration with other AWS services.
- Docker — the packaging format every modern deploy target understands. Build once, run the same image locally, in CI and in production.
- Kubernetes (managed: EKS, DOKS, GKE) — the right choice once you have more than a handful of services, need rolling updates, autoscaling and policy-driven networking. For a single service it is usually overkill; for a microservices estate it quickly pays for itself.
A VPS or managed cloud service is required to run this architecture end-to-end — the local docker-compose setup is for development, not for serving traffic.
Next steps & related tutorials
Keep the momentum going with the next tutorial in this learning path:
- [Next: API Rate Limiting in Spring Boot with Bucket4j and Redis](/blog/api-rate-limiting-in-spring-boot)
- [Next: Building REST APIs with Spring Boot: A Complete Guide](/blog/building-rest-apis-with-spring-boot)
- [Next: Spring Boot + Kafka — Build a Real-Time Messaging System](/blog/spring-boot-kafka-tutorial)
- [Next: Spring Boot + Redis Caching — Make Your API 10× Faster](/blog/spring-boot-redis-caching)
Source Code
Get the full project on GitHub
More From the Channel
Follow the full tutorial series on YouTube
The MasterLabSystems channel publishes in-depth, project-based tutorials on Java, Spring Boot, microservices, Docker, Kubernetes, AWS and DevOps — the same topics covered on this site, with full code walkthroughs.
Stay in the Loop
Get the next tutorial in your inbox
Related tutorials
API Rate Limiting in Spring Boot with Bucket4j and Redis
Protect your APIs from abuse with per-user and per-IP rate limiting using Bucket4j, Redis and a clean filter-based implementation.
Building REST APIs with Spring Boot: A Complete Guide
Design and build a production-ready REST API with Spring Boot — proper layering, DTOs, validation, error handling and testing.
Spring Boot + Kafka — Build a Real-Time Messaging System
Produce and consume Kafka messages from Spring Boot with proper serialization, error handling and consumer groups.