Redis: More Than a Cache
Redis is an in-memory data structure store. Most people use it as a cache, but its data types enable session storage, real-time leaderboards, rate limiting, pub/sub messaging, and job queues — all with sub-millisecond latency.
Data Types Overview
| Type | Use Case | Example |
|---|---|---|
| String | Cache, counters, sessions | Page cache, rate limit counter |
| Hash | Object storage | User profile, product details |
| List | Queues, activity feeds | Job queue, recent messages |
| Set | Unique collections, tags | Online users, unique visitors |
| Sorted Set | Rankings, time-series | Leaderboard, priority queue |
| Stream | Event log, message queue | Activity log, event sourcing |
Strings
# Basic key-value
SET user:session:abc123 "{\"userId\": 42, \"role\": \"admin\"}"
GET user:session:abc123
# With expiration (TTL)
SET cache:page:/home "<html>...</html>" EX 3600 # expires in 1 hour
# Atomic counter
INCR api:rate:user:42 # increment by 1
INCRBY api:rate:user:42 5 # increment by 5
DECR api:rate:user:42 # decrement by 1
# Set only if not exists (distributed lock)
SET lock:order:123 "worker-1" NX EX 30 # NX = only if not existsHashes (Objects)
# Store object fields individually
HSET user:42 name "Alice" email "alice@example.com" role "admin"
HGET user:42 name # "Alice"
HGETALL user:42 # all fields and values
HINCRBY user:42 login_count 1 # atomic field increment
# Better than storing JSON strings — update single fields without parsingLists (Queues)
# Job queue
LPUSH queue:emails "{\"to\": \"user@example.com\", \"subject\": \"Welcome\"}"
RPOP queue:emails # pop from the right (FIFO)
BRPOP queue:emails 30 # blocking pop (wait up to 30s for new item)
# Recent activity (keep last 100)
LPUSH activity:user:42 "Logged in"
LTRIM activity:user:42 0 99 # keep only last 100 entries
LRANGE activity:user:42 0 9 # get last 10Sets (Unique Collections)
# Track online users
SADD online:users "user:42" "user:17" "user:88"
SISMEMBER online:users "user:42" # true
SCARD online:users # count: 3
SMEMBERS online:users # all members
# Set operations
SINTER tag:javascript tag:react # users who know both
SUNION tag:javascript tag:python # users who know either
SDIFF tag:javascript tag:react # JS devs who don't know ReactSorted Sets (Rankings)
# Leaderboard
ZADD leaderboard 1500 "player:alice"
ZADD leaderboard 2200 "player:bob"
ZADD leaderboard 1800 "player:charlie"
ZRANK leaderboard "player:bob" # rank (0-based)
ZREVRANGE leaderboard 0 9 WITHSCORES # top 10
ZINCRBY leaderboard 100 "player:alice" # add 100 points
# Rate limiting with sliding window
ZADD rate:user:42 1682345678 "req:1"
ZRANGEBYSCORE rate:user:42 (now-60) +inf # requests in last 60sCommon Patterns
# Node.js with ioredis
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);
// Cache with fallback
async function getCached(key, fetchFn, ttl = 3600) {
const cached = await redis.get(key);
if (cached) return JSON.parse(cached);
const data = await fetchFn();
await redis.set(key, JSON.stringify(data), 'EX', ttl);
return data;
}
// Distributed lock
async function withLock(key, fn, ttl = 30) {
const acquired = await redis.set(`lock:${key}`, '1', 'NX', 'EX', ttl);
if (!acquired) throw new Error('Lock not acquired');
try {
return await fn();
} finally {
await redis.del(`lock:${key}`);
}
}Format your data: JSON Formatter — format Redis JSON values for readability.