AlgoMaster Logo

Key-Value Stores

High Priority14 min readUpdated July 4, 2026
AI Mock Interview

Practice this topic in a realistic system design interview

Listen to this chapter
Unlock Audio

Not every system needs joins, complex filters, or a relational schema. Sometimes the application already knows exactly what it wants: "give me the session for this session ID" or "give me the cached product for this product ID."

A key-value store is built for that kind of work. It stores a value under a key, then lets you fetch the value later with the same key. Think of it like a very fast dictionary or map.

The tradeoff is simple: key-value stores are fast because they keep the access pattern simple. They usually do not join records, search inside every field, or enforce a detailed schema. Instead, they are good at direct reads, writes, deletes, counters, expirations, and a few small data structures.

The key often tells you the job: session:abc123 for session data, cache:product:555 for a cached product response, or rate:user:1001:minute for a request counter.

You will see this model in caches, session stores, rate limiters, leaderboards, feature flags, and databases that handle very high request volume, such as DynamoDB-style systems.

This chapter explains how key-value stores work, where they shine, and where they become the wrong tool.

Loading simulation...

1. The Key-Value Model

A key-value store has two parts:

  • the key, which is the name or ID used to find the data
  • the value, which is the data stored under that key

The key is usually a string or a binary value. The value might be a plain string, JSON, a binary object, a counter, a hash, a set, a list, or another type supported by the database.

Basic Operations

The basic API is intentionally small:

  • GET key returns the value for a key
  • SET key value stores or replaces a value
  • DEL key removes a key
  • EXISTS key checks whether a key is present

Many stores also support:

  • EXPIRE key ttl, which removes a key after a time limit
  • INCR key, which safely increments a numeric value

The important point is that the database can go straight to the key. It does not need to plan a complex query, join tables, or search through many fields.

The exact speed depends on where the data lives, how large the value is, how far away the database is on the network, whether the data is copied to other machines, and how fresh each read must be.

In-memory systems such as Redis or Memcached are common when very fast reads and writes matter. Durable distributed systems such as DynamoDB are usually a little slower, but they can keep data safely over time and scale across many machines.

2. Key Design

In a key-value store, the key is the main way to reach data. Good key design makes the system easier to read, debug, scale, and operate.

Use Predictable Names

A consistent naming style makes keys easy to understand and group. Prefixes are especially useful because they show what kind of data a key holds.

Prefixes also help avoid accidental name conflicts. For example, user:1001:profile and session:1001 can safely mean different things.

Keep Keys Compact

Keys take memory and storage too. A long key does not matter much in a small system, but it matters when you have tens or hundreds of millions of keys.

Prefer:

Avoid:

Avoid Hot Keys

A hot key is a key that receives far more traffic than most other keys. One viral post, one popular product, or one global counter can overload the machine that owns that key.

Common fixes include:

  • split one busy counter into several smaller counters
  • cache popular read-only values closer to the application
  • add a little randomness to expiration times so many keys do not expire at once
  • avoid putting all users or tenants behind one shared key
  • choose keys that spread writes across many machines

3. Common Use Cases

These patterns show up again and again in production systems.

Caching

Caching is the classic key-value use case. The real data stays in a durable database. The key-value store keeps a faster temporary copy of data that is read often.

Cache-aside flow:

  1. Read from cache.
  2. On hit, return the cached value.
  3. On miss, read from the database.
  4. Store the result in cache with a TTL.
  5. Return the value.

Caching reduces load on the main database and makes repeated reads faster. The downside is freshness. A cached value may be older than the database value until it expires or the application removes it.

Session Storage

Sessions are a natural fit because every request usually carries a session ID.

The access pattern is simple: read the session by ID, update it if needed, and let it disappear automatically after the TTL.

Rate Limiting

Rate limiters often use counters with expiration.

Each request increments the counter and checks whether the user is still under the limit.

The increment must be atomic, which means the store performs it as one safe operation. If the application reads the number and then writes a new number itself, two requests can race and let too many requests through.

Leaderboards

Some key-value stores provide sorted sets or similar structures. Redis sorted sets are a common example.

This works well for questions like "who are the top 10 players today?" or "what is this user's rank?" It is not a good fit for broad analytics across many fields.

Temporary Application State

Shopping carts, password reset tokens, one-time codes, feature flag snapshots, and short-lived workflow state can all fit well. The pattern is the same: the application knows the key, and the data naturally expires.

4. Redis and Memcached

Redis and Memcached are common in-memory key-value systems. Both are often used for caching, but they are not the same tool.

Redis

Redis stores data mainly in memory and supports several data structures. Strings hold cached values, counters, and tokens. Hashes store small objects with fields.

Sets hold unique members for tags and membership checks. Sorted sets back leaderboards and ranked lists. Lists serve as simple queues or recent-item buffers, and streams are append-only event logs.

Redis also supports expiration, Lua scripts, transactions, replication, clustering, and persistence options.

Redis licensing changed in recent years. Redis moved away from the old BSD license in 2024, and Redis 8 added AGPLv3 as an available license in 2025.

The Linux Foundation also started Valkey, a community fork based on the last BSD-licensed Redis version. For many everyday cache use cases, Redis and Valkey feel very similar because they share the same roots and many of the same commands.

Memcached

Memcached is simpler. It is mostly a distributed in-memory cache for string or binary values. It does not provide Redis-style data structures, persistence, streams, or rich server-side operations.

That simplicity can be a strength. If you only need a large, fast, disposable cache, Memcached can be easy to understand and operate.

5. Persistence and Durability

Key-value stores are not all the same. Some are disposable caches. Some are durable primary databases.

In-memory caches such as Redis and Memcached hold fast cached or temporary data. If they lose data, the system should usually be able to rebuild it from somewhere else.

Durable distributed key-value databases such as DynamoDB, ScyllaDB, Aerospike, and Riak can act as primary storage. In that case, the key-value store holds the official copy of the data.

Embedded key-value engines such as RocksDB, LevelDB, and BadgerDB are often used inside other databases or local applications. Coordination systems such as etcd, Consul KV, and ZooKeeper-style services store small but important facts like configuration, service membership, and leader election state.

Redis Persistence

Redis can write data to disk, but you must choose how much durability you need.

ModeHow It WorksTrade-off
SnapshotWrites a copy of the data every so oftenFast restart, but recent writes can be lost
Append-only fileLogs write commands to diskSafer writes, but more disk and recovery work
BothUses snapshots and append-only loggingCommon practical compromise

The diagram below shows the basic idea: a write reaches memory first, then Redis may also write it to disk depending on the persistence mode.

Do not assume Redis persistence behaves like a transactional database. It can be durable enough for many workloads, but the settings matter.

Durable Key-Value Stores

Durable key-value databases store data on disk or other long-lived storage and copy it across machines for availability. DynamoDB is a familiar managed example. These systems usually start with a primary key model and may add sort keys, conditional writes, extra lookup paths called secondary indexes, and streams.

They are a better fit when the key-value store is the official place where the data lives.

6. Distribution and Scaling

Key-value stores scale by splitting keys across machines. This is often called partitioning or sharding.

The router maps each key to a shard. This works well for single-key operations because each request has a clear owner.

Multi-Key Operations

Multi-key operations are harder. If two keys live on different shards, the system must either coordinate across machines or reject the operation.

Redis Cluster handles this with hash slots. Keys that must be used together can be placed in the same slot with hash tags.

Both keys use the user:1001 tag for routing, so they can live on the same shard.

Consistency

Distributed key-value stores make different consistency choices. In plain terms, consistency is about how fresh and reliable a read is after a write.

ModelWhat It MeansTypical Example
Strong readA read returns the latest write the system has acceptedetcd, DynamoDB consistent reads
Eventual readA read may briefly return an older valuereplicated caches, DynamoDB default reads
Local single-node readOne node sees its own reads and writes in orderstandalone Redis

The right choice depends on the data. An older product page cache may be fine. An older permission decision may be dangerous.

7. Atomicity and Locks

Single-key atomic operations are one of the most useful features of key-value stores. Atomic means the store performs the operation as one indivisible step.

Examples:

  • increment a counter
  • set a value only if it does not exist
  • update a TTL
  • add a member to a set
  • append an item to a stream

Conditional Writes

Conditional writes help prevent lost updates.

This says: set the key only if it does not already exist, and expire it after 30 seconds.

Distributed Locks

Distributed locks are easy to use badly. A lock with a TTL is really a lease: "I own this for a limited time." That does not guarantee perfect safety by itself. The process holding the lock may pause, the network may split, or the lease may expire while the work is still running.

For low-risk coordination, a Redis lease can be enough. For high-value correctness, prefer a system designed for coordination, such as etcd, or use fencing tokens. A fencing token is a number that increases every time a lock is granted, so the final resource can reject an old worker that shows up late.

8. Access Patterns and Limits

Key-value stores are excellent when access is direct: the application knows the key and wants one value.

Good FitPoor Fit
Get session by session IDFind sessions by browser or city
Get product cache by product IDSearch products by text
Increment rate counter by user IDCompute analytics across all users
Get cart by user IDJoin carts with orders and payments
Store feature flag by keySearch feature flags by any field

If you need to query by value, join related records, scan large ranges, or calculate totals across many records, use a database built for those patterns.

Some key-value databases add secondary indexes, which let you look up data by fields other than the main key. That can be useful, but it changes the tradeoff. The system is no longer doing only simple key-value lookups.

9. When to Choose Key-Value Stores

Choose a key-value store when:

  • The application knows the key. Reads and writes are mostly direct lookups.
  • Fast responses matter. The system is on a hot request path.
  • Values are simple. The database does not need to understand much about the value.
  • TTL is useful. Data should expire naturally.
  • Single-key atomic operations are enough. Counters, leases, sets, and conditional writes cover the need.
  • Splitting by key works. The workload can be spread across many keys without constant coordination between shards.

Consider another database when:

  • You need rich queries. Use relational, document, search, or analytical storage.
  • Relationships are central. Use relational or graph models.
  • The data is the official copy and must not be lost. Use a durable key-value database or another primary database, not a disposable cache.
  • Hot keys dominate traffic. Fix the data model before adding nodes.
  • Cross-key transactions are common. A relational database or transactional distributed database may be easier to reason about.

Summary

Key-value stores trade flexible querying for a small, fast, predictable access pattern. The model is just a key plus a value, and the main path is a direct lookup by key.

Their strengths are fast responses, simplicity, TTLs, counters, and caching. They scale by spreading keys across machines. Their main weakness is any query that does not start with a known key.

The real design question is: can the product access this data by key most of the time? If yes, the model stays beautifully simple. If no, that simplicity becomes a wall you keep running into.

Quiz

Key-Value Stores Quiz

10 quizzes