Redis Caching Strategies for Modern Apps

How to effectively use Redis to speed up your applications using Write-through and Cache-aside patterns.

Published: January 15, 2024

When your application starts to scale, the database inevitably becomes the primary bottleneck. Every read query takes time, and under heavy traffic, your database can crawl to a halt. The standard industry solution? Caching.

Redis is the gold standard for in-memory caching. However, simply "putting Redis in front of the database" isn't a magic bullet. You need a deliberate caching strategy to ensure data consistency and optimal performance. Let's explore the most common patterns and when to use them.

1. Cache-Aside (Lazy Loading)

This is the most common and versatile caching strategy. The application talks directly to both the cache and the database.

How it works:

  1. The application requests data from the cache first.
  2. If the data is found (Cache Hit), it's returned immediately.
  3. If the data is not found (Cache Miss), the application fetches it from the database.
  4. The application then writes the fetched data into the cache for next time, and returns it to the user.

Pros:

  • The cache only contains data that is actually requested, making it highly memory-efficient.
  • If Redis goes down, the system can gracefully degrade by falling back directly to the database.

Cons:

  • There is a slight latency penalty on a cache miss, as three trips are made (Cache -> DB -> Cache).
  • Data can become stale if it gets updated in the database but the cache isn't invalidated.

2. Write-Through

In this pattern, the application treats the cache as the primary data store. The cache is then responsible for writing to the database synchronously.

How it works:

  1. The application writes new data directly to the cache.
  2. The cache synchronously updates the database.
  3. Once the database write is confirmed, the operation completes.

Pros:

  • Data in the cache is never stale. It is always perfectly in sync with the source of truth.
  • Reads are incredibly fast, as the cache is always warm.

Cons:

  • Writes incur higher latency because they have to wait for both the cache and the database to confirm the save.
  • The cache can fill up with data that might never be read again, wasting expensive memory.

3. Write-Behind (Write-Back)

This is similar to Write-Through, but the cache updates the database asynchronously in the background.

How it works:

  1. The application writes data to the cache.
  2. The cache immediately acknowledges the write to the application, so the user isn't kept waiting.
  3. In the background, the cache periodically batches and syncs the updated data to the database.

Pros:

  • Incredible write performance. The application doesn't have to wait for a slow database connection.
  • Excellent for write-heavy workloads (e.g., tracking views, processing likes, or real-time analytics).

Cons:

  • High risk of data loss. If the cache crashes before syncing to the database, that data is gone forever.
  • Highly complex to implement correctly and debug.

The Invalidation Problem

Phil Karlton famously said: "There are only two hard things in Computer Science: cache invalidation and naming things."

When data changes in your primary database, your cache becomes stale. To solve this safely, always use a TTL (Time To Live) on your cache keys. Even if your manual invalidation logic fails or a server restarts unexpectedly, the TTL ensures the bad data will eventually expire on its own.

Code
// Example: Storing a user profile with a 1-hour TTL
await redis.set(`user:${userId}`, JSON.stringify(profile), 'EX', 3600);

Conclusion

There is no "one size fits all" caching strategy. For the vast majority of modern web apps, the Cache-Aside pattern paired with sensible TTLs is the perfect balance of performance and simplicity. Understand your read/write ratios, consider the cost of stale data, and choose the pattern that best fits your workload.