Redis
Write-through Cache
Database Management
Data Storage
System Architecture

Write-through cache Redis

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Write-through caching is a consistency-first pattern where every successful write updates both the cache and the durable store before the operation is considered complete. Redis is often used in this pattern, but Redis itself is only the cache layer; your application still has to coordinate the write.

What Write-Through Means With Redis

In a write-through design, the application does not wait for a later background sync. When a user updates data, the service writes the new value to the primary database and also writes the same value to Redis during the same request path.

That gives you two useful properties:

  • reads are fast because Redis already has the current value
  • cache misses are less common because hot keys are populated on write

The tradeoff is write latency. A request is now waiting for both systems, so your write path is slower and has more failure cases than a cache-aside approach.

It is also important to be precise about terminology. Redis does not magically become write-through by turning on persistence. Redis persistence controls how Redis saves its own state. Write-through describes how your service coordinates Redis with another source of truth such as PostgreSQL or MySQL.

A Minimal Write-Through Flow

The usual sequence is:

  1. validate the incoming data
  2. write to the database in a transaction
  3. update Redis with the committed value
  4. return success only if both steps finish as expected

The example below is runnable Python. It uses dictionaries to stand in for a database and a Redis cache so the behavior is easy to inspect:

python
1import json
2
3class FakeDatabase:
4    def __init__(self):
5        self.rows = {}
6
7    def save_user(self, user_id, profile):
8        self.rows[user_id] = profile.copy()
9
10    def load_user(self, user_id):
11        return self.rows.get(user_id)
12
13class FakeRedis:
14    def __init__(self):
15        self.values = {}
16
17    def set(self, key, value):
18        self.values[key] = value
19
20    def get(self, key):
21        return self.values.get(key)
22
23
24db = FakeDatabase()
25cache = FakeRedis()
26
27
28def save_user_profile(user_id, profile):
29    db.save_user(user_id, profile)
30    cache.set(f"user:{user_id}", json.dumps(profile))
31
32
33def get_user_profile(user_id):
34    cached = cache.get(f"user:{user_id}")
35    if cached is not None:
36        return json.loads(cached), "cache"
37    row = db.load_user(user_id)
38    if row is None:
39        return None, "miss"
40    cache.set(f"user:{user_id}", json.dumps(row))
41    return row, "database"
42
43
44save_user_profile(7, {"name": "Mina", "plan": "pro"})
45print(get_user_profile(7))

In production, replace FakeRedis with a real Redis client and replace the fake database class with your ORM or SQL layer. The control flow stays the same.

When It Fits Well

Write-through is a good choice when stale reads are expensive or confusing. User profiles, feature flags, pricing rules, and account settings are common examples. After a successful update, the next read should return the same value no matter whether it hits Redis or the database.

It is a weaker fit for high-volume event streams or analytics counters where write throughput matters more than immediate cache freshness. In those systems, write-behind, batching, or cache-aside usually scales better.

Design Choices That Matter

You still need to decide which system is authoritative. In most systems the database is the source of truth, and Redis is a fast copy. That means database failures should fail the request. If the database write fails but the cache write succeeds, you have created incorrect cached state.

A safer pattern is database first, cache second, with explicit handling for partial failure. If the database commit succeeds and Redis is temporarily unavailable, you can either fail the request and retry, or return success and enqueue a cache repair job. Which choice is correct depends on how much inconsistency your application can tolerate.

Common Pitfalls

The most common mistake is treating Redis persistence as if it solves cache consistency with another database. It does not. AOF or RDB helps Redis recover its own data, but it does not synchronize Redis with PostgreSQL or any other store.

Another mistake is writing the cache before the database. If the database step fails, readers can observe data that never actually committed.

Teams also forget about expiration. A write-through cache can still use TTL values, but if the TTL is too short, you lose much of the point of populating the cache on writes. Set expirations deliberately.

Summary

  • Write-through means the application updates the database and Redis on the same write path.
  • Redis does not provide cross-system write-through automatically; your service logic implements it.
  • The pattern favors consistency and predictable reads, at the cost of slower writes.
  • Database-first ordering is usually safer than cache-first ordering.
  • Use it for data where stale reads hurt more than extra write latency.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.