System Design Interview Questions: Caching Strategies

Reviewed by Mark Dickie · Last updated

6 questions on this page you can answer and see marked on the spot. Go to the first one

Caching strategies are techniques that store frequently accessed data closer to the consumer to reduce latency, database load, and cost. For a system design interview, you should know the four core write patterns (cache-aside, write-through, write-back, write-around), the common eviction policies (LRU, LFU, FIFO), and the invalidation tradeoffs that determine consistency. Interviewers want to see you reason about when a cache helps, what staleness your system can tolerate, and how cache-miss thundering herds degrade under load. The questions below let you check these fundamentals before you walk into the whiteboard.

What write patterns should I know for a caching interview?

PatternWrite pathRead pathStaleness risk
Cache-asideApp writes to DB, then invalidates cacheApp checks cache, falls back to DB on missModerate — stale reads between invalidation and next load
Write-throughApp writes to cache and DB togetherCache hit serves all readsLow — cache stays consistent with DB
Write-backApp writes to cache only; cache flushes to DB laterCache hit serves readsHigh — data loss risk if cache fails before flush
Write-aroundApp writes to DB only, cache loads on read missApp checks cache, falls back to DBModerate — first read after write is a miss

How do eviction policies affect cache hit rate?

  1. LRU evicts the least recently used entry, which works well when access patterns follow recency — most reads touch recently fetched data.
  2. LFU evicts the least frequently used entry, which is better when some keys stay popular over time regardless of recency.
  3. FIFO evicts the oldest inserted entry. It is the simplest to implement but ignores access frequency entirely.
  4. TTL-based eviction discards entries after a fixed time. This is useful for data that goes stale on a schedule, though it does not track access patterns.

What cache invalidation question comes up most often?

Cache invalidation is the part candidates stumble on because it forces a consistency vs. latency tradeoff. You should be ready to explain write-through invalidation, where the cache stays in sync with DB writes; explicit invalidation, where the application deletes cache keys after a DB update; and TTL-based expiry, where cache entries expire after a set window.

The hardest follow-up asks how you handle invalidation in a distributed cache with eventual consistency. Your answer should address cache stampedes, where many requests miss the cache at once and all hit the database. Common mitigations are request coalescing, probabilistic early expiry, and locking the cache-miss path so only one request repopulates the key.

Key facts

  • Tarmac has 22 System Design interview questions on this topic, 10 of them on this page, at difficulty 1–4 of 5.
  • Tarmac tracked 3,763 job postings asking for System Design in September 2026.
  • Roles asking for System Design advertise a median base salary of US$180,000, across 1,181 job postings as of September 2026.
  • Tarmac last reviewed these System Design interview questions on 14 September 2026.

At a glance

Questions10 shown · 22 in the bank
Difficulty1–4 of 5
FormatsMultiple answer, True / false, Fill in the blank, Multiple choice, Short answer, Flashcard, Ordering, Design exercise

What you'll review

  1. caching strategies
  2. cdn edge
  3. cache eviction
  4. id generation

Practice questions

Try one before you open the answer. Pick an option and press Check; it's marked on the spot.

Consider a read-heavy service that uses the cache-aside (lazy loading) pattern with a Redis cache in front of a relational database. Which of the following statements about this pattern are true? Select all that apply.#

Options

Pick every one that applies.

Show answer

Cache-aside (lazy loading) has the application fill the cache on a read miss, so only requested data gets cached. A database update does not refresh the cache automatically, so stale values can persist until the entry is invalidated or expires. The database stays the source of truth and is read directly on misses.

Why:

In cache-aside, the application owns the cache logic: on a miss it queries the database and populates the cache, so only requested data is cached. The database is the source of truth and is read directly on misses. Nothing in the database engine propagates writes into Redis, so after an update the cached copy stays stale until the application invalidates it or the TTL expires. The statement claiming the cache is the system of record is false because the database remains authoritative.

Your global app serves large static assets (images, JS bundles, video) and origin egress plus latency are hurting. You put a CDN / edge cache in front. Which outcomes are correct expectations of this change?#

Options

Pick every one that applies.

Show answer

The correct expectations are that cached assets are served from edge PoPs close to users (cutting round-trip latency), origin load and egress drop because the CDN absorbs repeat requests for cacheable content, and Cache-Control/TTL headers govern how long edges serve content before revalidating. Highly personalized per-user responses are not trivially cacheable at a shared edge, and edges do not instantly reflect origin changes — stale objects live until TTL or an explicit purge.

Why:

A CDN caches content at edge points of presence near users, so it lowers latency and offloads repeat requests from the origin, cutting load and egress, with freshness controlled by Cache-Control/TTL and revalidation. The wrong options are classic edge-caching traps. Personalized, per-user dynamic responses are generally not cacheable at a shared edge — caching them risks leaking one user's data to another, so they need private/no-store handling or edge-compute personalization, not naive caching. And edges do not instantly reflect origin changes: cached objects live until their TTL or an explicit purge/invalidation, which is precisely why a bad asset deploy can keep serving stale content until you invalidate the cache or bust the URL.

In a write-back (write-behind) cache, a write is acknowledged to the client once it is stored in the cache, and the backing data store is updated later, asynchronously. True or false?#

Options

Show answer

A write-back cache acknowledges a write as soon as it is stored in the cache, and the backing store is updated later, asynchronously. This lowers write latency and database load, but writes not yet flushed can be lost if the cache fails before persisting them.

Why:

In a write-back cache, the application writes to the cache and receives an acknowledgement immediately. The cache flushes the modified data to the backing store later, in the background or in batches. This reduces write latency and database load, but any writes still unflushed when the cache node fails can be lost, so the statement is true.

A cache that is full must evict an entry to admit a new one. The eviction policy that removes the entry whose most recent access is the oldest is abbreviated _____.#

Show answer

A cache that is full must evict an entry to admit a new one. The eviction policy that removes the entry whose most recent access is the oldest is abbreviated LRU.

Why:

LRU stands for Least Recently Used. It evicts the entry whose last access is furthest in the past, on the assumption that recently used data is likely to be used again. This is distinct from LFU (least frequently used), which counts access frequency rather than recency, and from FIFO, which evicts by insertion order.

A read-heavy product catalog uses a cache in front of the database. The team wants fresh reads immediately after a write with the lowest steady-state read latency, accepting slightly slower writes. Which caching strategy best fits?#

Options

Show answer

Use a write-through cache: write to the cache and the database synchronously on every write. The just-written value is already in cache for the next read, giving fresh reads immediately at the cost of a slightly slower write — exactly the trade described. Cache-aside only populates on a read miss, and TTL or write-behind strategies both permit a window of staleness.

Why:

Write-through updates the cache and the database in the same write path, so the just-written value is already in cache for the next read — you get fresh reads immediately at the cost of a slower write, exactly the trade the team accepted. Plain cache-aside only populates the cache on a read miss, so the entry written can be stale until the next miss (and a delete-on-write is needed to avoid serving the old value). Write-behind acknowledges before the DB is durable, trading consistency and durability for write speed — the opposite of the stated priority. TTL-only caching guarantees staleness for up to the TTL window, which violates the "fresh immediately" requirement.

Explain cache-aside versus write-through caching, and give one failure mode of each.#

Show answer

With cache-aside the application reads from the cache and, on a miss, loads from the database and populates the cache itself; writes update the database and invalidate or delete the cached entry. Its failure mode is a stale read: between a write that fails to invalidate (or two concurrent reads racing a write) the cache can serve outdated data. With write-through the application writes through the cache layer, which synchronously writes to the database before acknowledging, so the cache is always consistent on write. Its failure mode is added write latency and the fact that data nobody reads still gets cached, wasting memory.

Why:

Cache-aside (lazy loading) keeps cache population in the application: read the cache, fall back to the store on a miss, and explicitly invalidate on write — simple and resilient (a cache outage just means more DB load) but prone to stale reads under races. Write-through routes writes through the cache so it is always fresh, at the cost of write latency and caching cold data; it pairs well with a read-through path. The right choice depends on read/write ratio and tolerance for staleness.

Describe the cache-aside (lazy-loading) caching strategy and its main failure mode.#

Show answer

In cache-aside the application code owns the cache: on a read it checks the cache first, and on a miss it loads from the database, populates the cache, and returns. Writes go to the database and then invalidate (or update) the cache entry. Its main failure mode is the thundering herd / cache stampede — when a hot key expires, many concurrent requests all miss and hammer the database at once. Mitigate with request coalescing (single-flight), a short lock per key, or probabilistic early refresh.

Why:

Cache-aside is the most common strategy because the app stays in control and the cache only ever holds data that was actually requested. The trade-offs are an extra round trip on misses and the need to manage invalidation carefully, since stale entries linger until they expire or are explicitly evicted.

Order the components a cacheable read request passes through on its way to the data, from the client outward.#

Put these in order

Show answer

A cacheable read passes through progressively narrowing caches before reaching the data:

  1. The client request hits the nearest CDN / edge point of presence.
  2. On a CDN miss it forwards to the regional load balancer.
  3. The load balancer routes to a healthy application server.
  4. The app checks the in-memory cache (e.g. Redis) for the key.
  5. On a cache miss it queries the database of record.
Why:

Each layer exists to absorb load before it reaches the next, more expensive one: the CDN serves cacheable responses at the edge, the load balancer spreads survivors across stateless app servers, the app cache shields the database from hot reads, and only genuine misses reach the database. Designing the read path as a cascade of progressively-narrowing caches is the core of scaling reads cheaply.

Design a URL shortener (think Bitly / TinyURL).#

Show answer

Requirements. Two operations dominate: create (write a mapping, optionally with a custom alias and expiry) and redirect (look up a code and 30x to the long URL). The system is overwhelmingly read-heavy (100:1), so the redirect path is what we optimise. I'd confirm: are custom aliases required (yes), do links expire (optional TTL), and how precise must click counts be (approximate/eventually-consistent is fine). I'd use a 302 (temporary) redirect so we keep serving redirects through our system and can still count clicks; a 301 would let browsers cache and bypass us.

Capacity. ~40 writes/sec average, ~200/sec peak; ~4K reads/sec average, ~20K peak. Storage: ~6B links over 5 years; at ~500 bytes/row (code, URL, metadata) that's ~3 TB — comfortably shardable. Keyspace: base62 with 7 characters gives 62⁷ ≈ 3.5×10¹² codes, far more than 6B, so 7 chars (often padded to a fixed length) is plenty. The hot working set (recently/ popularly accessed links) is a small fraction of 6B, so a cache of tens of GB covers the bulk of redirect traffic.

Data model. A single mapping table/collection keyed by the short code: code (PK) → long_url, created_at, expires_at, owner_id. Point lookups by primary key suit a key-value store (DynamoDB/Redis-backed) or a sharded relational table sharded by code. Click counts live separately — incrementing a counter on every redirect would put write load on the read path — so clicks are emitted as events and aggregated asynchronously.

Short-code generation. Generate a unique 64-bit id (a distributed counter handed out in ranges per server, or a Snowflake-style id) and base62-encode it to get the short code; this guarantees uniqueness with no collision checks and no hotspot from a single shared counter. Custom aliases are written directly with a uniqueness check and stored in the same table, reserving that code. (A hash-of-URL scheme is the alternative but needs collision handling and breaks idempotency for duplicate URLs.)

Read/write paths. Write: allocate id → base62 → insert mapping → return the short URL. Redirect: a load balancer / CDN fronts stateless app servers; the server does a cache-aside lookup (code → long_url) in Redis, falling back to the store on a miss and populating the cache, then returns a 302. This keeps p99 well under 100 ms for cache hits. Expiry is enforced by TTL on both the row and the cache entry. Each redirect fires a lightweight click event onto a queue (Kafka) that a consumer aggregates into per-link counts.

Bottleneck & scaling. The bottleneck is the redirect read path at peak. We scale it with cache layers (most reads never touch the store), read replicas, and sharding the mapping store by code so lookups stay single-shard. Id generation scales by handing each server an independent id range (or using Snowflake), avoiding a single global counter as a SPOF. At 10× traffic, the cache absorbs most of it; we add cache nodes and replicas and, if needed, push redirects further to the edge.

Why:

A URL shortener is the canonical warm-up design: it forces a clean separation of a heavily read-optimised redirect path from a comparatively rare write path. The two pivotal decisions are short-code generation (a base62-encoded distributed id avoids both collisions and the hotspot of a single shared counter) and caching (cache-aside on code→URL, fronted by a CDN/LB, is what meets the latency budget when reads outnumber writes 100:1). Click counting is deliberately moved off the redirect path and made asynchronous so analytics never slow a redirect. The dominant bottleneck is the redirect read path, scaled by caching, read replicas, and sharding the mapping store by code.

Related interview questions

Job market

See system-design salaries and hiring demand from live job postings.

The other 12 questions

This page shows 10 and marks what you pick. That's as far as a page can go. A free account opens the other 12 and keeps every answer. What you miss comes back until it's right: after a day, then at longer gaps.

Start with this topic

Free · the whole bank · 100 marked answers per 30 days · written feedback on the paid plan

Interview booked? Practise the job ad instead

What moved, monthly

One email a month when the bulletin comes out: what moved in the markets we track, and the new question topics we published. Confirm your address to join. Unsubscribe any time.