Java & Spring Boot8 min read·

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.

Advertisement

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

bash
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

xml
<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

yaml
spring:
  data.redis:
    host: localhost
    port: 6379
  cache:
    type: redis
    redis:
      time-to-live: 600000
      cache-null-values: false
java
@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 add implements Serializable or configure a JSON serializer (recommended — it's debuggable in redis-cli).
  • Cache hit returns null for "missing" entries — Spring caches null too. Set cache-null-values: false and let misses repeat the DB call.
  • Annotations do nothing — self-invocation. @Cacheable is 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)

java
@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

View repo →
#Redis#Caching#Spring Boot#Performance

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