Key-Value Stores

beginner nosql redis dynamodb key-value caching

A key-value store is the simplest type of database. We give it a key, and it gives us back a value. That’s it. No columns, no schemas, no joins.

Think of it like a giant dictionary (or a HashMap/Object in code). We look up a word (key) and get the definition (value).

key: "user:42:session"  →  value: "eyJhbGciOiJIUzI1NiJ9..."
key: "product:99:price"  →  value: "2999"
key: "config:theme"      →  value: "dark"

Redis — in-memory, blazing fast (sub-millisecond reads), supports data structures like lists, sets, sorted sets, and hashes. The most popular choice for caching and real-time data.

Amazon DynamoDB — managed, serverless, massively scalable. Supports both key-value and document models. Pay per request or provisioned capacity.

etcd — distributed key-value store used by Kubernetes for storing cluster state. Focuses on consistency and reliability.

Memcached — pure in-memory cache. Simpler than Redis but faster for basic key-value caching because it’s multi-threaded.

Common Use Cases

Caching — store the result of an expensive query or computation. Next time, check the cache first.

// Pseudocode
cache.set("user:42", JSON.stringify(userData), { ttl: 3600 })  // cache for 1 hour
cached = cache.get("user:42")
if (cached) return JSON.parse(cached)  // cache hit!
// otherwise, query the database

Session Storage — store user sessions with an expiration time. Way faster than querying a database on every request.

Rate Limiting — count requests per user per time window.

Feature Flags — toggle features on/off without deploying code.

Leaderboards — Redis sorted sets are perfect for ranked lists.

Pub/Sub Messaging — Redis supports publish/subscribe for real-time communication.

Redis in Action

Redis isn’t just a simple key-value store. It supports rich data types:

# Basic key-value
SET user:42:name "Manish"
GET user:42:name                    # "Manish"

# With expiration (TTL)
SET session:abc123 "user_data" EX 3600    # expires in 1 hour
TTL session:abc123                         # seconds remaining

# Hash (like a mini-object)
HSET user:42 name "Manish" email "manish@example.com" age 25
HGET user:42 name                  # "Manish"
HGETALL user:42                    # all fields

# List (queue/stack)
LPUSH notifications:42 "New message!"
LPUSH notifications:42 "Order shipped!"
LRANGE notifications:42 0 -1       # get all

# Set (unique values)
SADD user:42:skills "JavaScript" "Python" "Go"
SISMEMBER user:42:skills "Python"   # true
SMEMBERS user:42:skills             # all skills

# Sorted Set (leaderboard)
ZADD leaderboard 1500 "player:1"
ZADD leaderboard 2200 "player:2"
ZADD leaderboard 1800 "player:3"
ZREVRANGE leaderboard 0 2 WITHSCORES  # top 3 players

Limitations

Key-value stores trade features for speed:

  • No complex queries — we can’t say “find all users where age > 25”. We can only look up by key.
  • No relationships — no joins, no foreign keys, no referential integrity.
  • No schema — the value is opaque to the database. It can’t index or search inside values (Redis hashes are a partial exception).
  • Memory constraints — in-memory stores like Redis are limited by available RAM. Data larger than memory needs disk-backed solutions.

When to Pick Key-Value

We always look up data by a known key
We need sub-millisecond response times
Data is simple (strings, counters, small objects)
We need TTL (time-to-live) for auto-expiration
We need to search by value or run complex queries
We need relationships between records
We need ACID transactions across multiple keys

In most real applications, key-value stores are used alongside a primary database, not as a replacement. PostgreSQL for the main data, Redis for caching and sessions. They complement each other.

In simple language, key-value stores are the fastest, simplest databases out there. Give it a key, get a value. No frills, no overhead. Use them for caching, sessions, and any scenario where we know exactly which key we want.