Last Updated: January 12, 2026
In the previous chapter, we explored document databases and their flexible JSON-based data model.
While document databases offer rich query capabilities over nested structures, sometimes you do not need any of that. Sometimes you just need to store a value and retrieve it later by a key. No queries. No indexes. No schema. Just pure, fast storage and retrieval.
This is the domain of key-value stores. They are the simplest database type: give it a key and a value, get the value back when you provide the key.
By doing less, key-value stores can be incredibly fast. We are talking sub-millisecond latency for reads and writes. Redis, the most popular key-value store, can handle over a million operations per second on a single server.
Think of a key-value store like a hash map that persists to disk. You have used hash maps in your code: constant-time lookups, simple API, no complex queries. Key-value stores bring that model to the database layer, with the addition of persistence, replication, and distributed scaling.
A key-value store is, at its core, a giant hash map. You store data as key-value pairs:
user:123:profile, session:abc123).The API is minimal:
| Operation | Description | Complexity |
|---|---|---|
GET key | Retrieve the value for a key | O(1) |
SET key value | Store a key-value pair | O(1) |
DELETE key | Remove a key-value pair | O(1) |
EXISTS key | Check if a key exists | O(1) |
Some stores add variations:
SETNX (set if not exists)SETEX (set with expiration)MGET/MSET (multi-key operations)INCR/DECR (atomic increment/decrement)Several design choices contribute to sub-millisecond performance:
1. Simple data access pattern. There is no query parsing, query planning, or index traversal. The key hashes directly to a memory location.
2. In-memory storage. Many key-value stores (Redis, Memcached) keep all data in RAM. Memory access is orders of magnitude faster than disk.
3. No schema overhead. Values are opaque blobs. The database does not parse, validate, or index them.
4. Minimal coordination. Single-key operations do not need locks or transaction coordination in most cases.
Keys are your only access path.
Keys consume memory. A key like user:1001 uses 10 bytes. A key like application:production:user:profile:identifier:1001 uses 51 bytes. At millions of keys, this adds up.
Colons (:) are conventional, but be consistent. Some tools use dots or slashes.
Stick to alphanumeric characters and simple separators for compatibility.
Key-value stores solve specific problems exceptionally well. Understanding these patterns helps you recognize when to reach for them.
The most common use case. Place a key-value store in front of your primary database to cache frequently accessed data:
User sessions need fast access on every request. Storing them in a key-value store is ideal:
Limit API requests per user or IP address:
Sorted sets in Redis make leaderboards trivial:
Shopping carts are temporary, per-user, and accessed frequently:
Redis supports publish/subscribe messaging:
Redis is the most popular key-value store, powering critical systems at Twitter, GitHub, Snapchat, and countless others. While it started as a simple key-value cache, it has evolved into a "data structure server" with rich capabilities.
Redis goes beyond simple strings. Each data type has specialized commands:
| Type | Description | Use Cases |
|---|---|---|
| String | Binary-safe string up to 512MB | Caching, counters, simple values |
| List | Linked list of strings | Queues, recent activity, timelines |
| Set | Unordered unique strings | Tags, unique visitors, set operations |
| Sorted Set | Set with scores | Leaderboards, priority queues, range queries |
| Hash | Field-value pairs | Objects, user profiles, counters per field |
| Stream | Append-only log | Event sourcing, message queues |
Beyond GET/SET, strings support:
Lists are doubly-linked lists, efficient for push/pop at either end:
Use case: Job queue
Hashes store objects without serialization overhead:
Why hashes vs. JSON strings:
Sorted sets maintain elements ordered by score:
Keys can have automatic expiration:
TTL is essential for:
Redis transactions group commands to execute atomically:
Commands are queued during MULTI and executed atomically on EXEC. However, Redis transactions are not rollback-safe. If a command fails, others still execute.
For true atomicity, use Lua scripts:
Key-value stores fall into two categories:
Data lives primarily in RAM with optional persistence to disk.
| Aspect | Characteristic |
|---|---|
| Speed | Sub-millisecond (memory access) |
| Capacity | Limited by RAM (typically 10s-100s GB) |
| Persistence | Optional (RDB snapshots, AOF log) |
| Use case | Caching, sessions, real-time features |
Data is durably stored to disk with replication for fault tolerance.
| Aspect | Characteristic |
|---|---|
| Speed | Low milliseconds (SSD access, network) |
| Capacity | Virtually unlimited (distributed storage) |
| Persistence | Always durable |
| Use case | Primary data store, configuration, coordination |
| Feature | Redis/Memcached | DynamoDB | etcd |
|---|---|---|---|
| Primary storage | RAM | SSD | SSD |
| Latency | < 1ms | 1-10ms | 1-10ms |
| Max size | RAM limit | Unlimited | Small (recommended < 8GB) |
| Durability | Optional | Guaranteed | Guaranteed |
| Scaling | Cluster mode | Automatic | Raft consensus |
| Best for | Cache, real-time | Primary KV store | Config, coordination |
For scale beyond a single server, key-value stores can be distributed across multiple nodes.
Redis Cluster automatically partitions data across multiple nodes:
{user:1001}:profile, {user:1001}:settings)DynamoDB is a fully managed key-value and document database:
etcd is a distributed key-value store designed for configuration and coordination:
Distributed key-value stores offer different consistency guarantees:
| Model | Description | Examples |
|---|---|---|
| Strong | Reads always see latest write | etcd, DynamoDB (consistent read) |
| Eventual | Reads may see stale data temporarily | DynamoDB (default), Cassandra |
| Read-your-writes | You see your own writes immediately | Redis (single node) |
The application manages the cache explicitly:
Pros: Simple, cache only what is accessed, tolerant of cache failures. Cons: First request is slow (cache miss), potential stale data.
Write to cache and database together:
Pros: Cache is always consistent with DB. Cons: Write latency includes both DB and cache, cache may store rarely-read data.
Write to cache immediately, persist to database asynchronously:
Pros: Very fast writes, can batch database operations. Cons: Risk of data loss if cache fails before persist, complexity.
Use Redis for distributed locks:
For production use, consider Redlock algorithm or Redis RedLock for multi-node scenarios.
Key-value stores are the right choice when:
Key-value stores may not fit when:
Key-value stores offer the simplest data model and the fastest performance:
| Aspect | Characteristic |
|---|---|
| Data model | Key-value pairs, no schema |
| Operations | GET, SET, DELETE, EXISTS |
| Performance | Sub-millisecond (in-memory) |
| Scaling | Sharding by key hash |
| Trade-off | Speed and simplicity vs query flexibility |
The next chapter explores wide-column stores, which extend the key-value model with column families for handling massive scale and high write throughput.