Redis in 2026: Caching, Sessions, and Real-Time Features You Actually Need
Every serious web app eventually hits a wall: the database is too slow, sessions don't scale, or real-time features feel impossible.
Redis solves all three.
This guide covers practical Redis patterns you'll actually use in production in 2026.
What Is Redis?
Redis is an in-memory data structure store — it lives in RAM, so reads/writes are microseconds-fast. It's used as:
- Cache — store expensive query results
- Session store — stateless HTTP sessions
- Message broker — pub/sub for real-time features
- Rate limiter — protect APIs from abuse
- Job queue — background task processing
In 2026, Redis is installed on virtually every production server.
Installation
# Docker (recommended for dev)
docker run -d -p 6379:6379 redis:alpine
# Node.js client
npm install ioredis
# Python client
pip install redis
Pattern 1: Caching Database Queries
This single pattern can make your app feel 10x faster.
// cache.js
const Redis = require('ioredis');
const redis = new Redis({ host: 'localhost', port: 6379 });
async function getCachedUser(userId) {
const cacheKey = `user:${userId}`;
// Check cache first
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
// Not cached — fetch from database
const user = await db.query('SELECT * FROM users WHERE id = ?', [userId]);
// Store in cache for 5 minutes
await redis.setex(cacheKey, 300, JSON.stringify(user));
return user;
}
// Invalidate cache when user updates
async function updateUser(userId, data) {
await db.query('UPDATE users SET ? WHERE id = ?', [data, userId]);
await redis.del(`user:${userId}`); // Clear stale cache
}
Before Redis: 150ms per request (DB query)
After Redis: 2ms per request (cache hit) — 98.6% faster
Pattern 2: Session Management
// Express session with Redis store
const session = require('express-session');
const RedisStore = require('connect-redis').default;
app.use(session({
store: new RedisStore({ client: redis }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
},
}));
// Now sessions scale horizontally — any server can serve any session
Pattern 3: Rate Limiting
Protect your API without a complex library:
async function checkRateLimit(ip, maxRequests = 100, windowSeconds = 60) {
const key = `rate_limit:${ip}`;
const current = await redis.incr(key);
if (current === 1) {
// First request — set expiry
await redis.expire(key, windowSeconds);
}
return {
allowed: current <= maxRequests,
remaining: Math.max(0, maxRequests - current),
total: maxRequests,
};
}
// Middleware
app.use(async (req, res, next) => {
const { allowed, remaining } = await checkRateLimit(req.ip);
res.set('X-RateLimit-Remaining', remaining);
if (!allowed) {
return res.status(429).json({ error: 'Too many requests' });
}
next();
});
Pattern 4: Pub/Sub for Real-Time Features
// Real-time notifications
const publisher = new Redis();
const subscriber = new Redis();
// Publish a message
async function notifyUser(userId, message) {
await publisher.publish(`user:${userId}:notifications`, JSON.stringify({
type: 'notification',
message,
timestamp: Date.now(),
}));
}
// Subscribe to messages
subscriber.subscribe('user:123:notifications');
subscriber.on('message', (channel, message) => {
const data = JSON.parse(message);
// Send to WebSocket client
sendToWebSocket(data);
});
// Use case: chat apps, live dashboards, collaborative tools
Pattern 5: Leaderboards with Sorted Sets
// Game/app leaderboard
async function updateScore(userId, score) {
await redis.zadd('leaderboard', score, userId);
}
async function getTopPlayers(count = 10) {
// Get top N players with scores
const results = await redis.zrevrangebyscore(
'leaderboard', '+inf', '-inf',
'WITHSCORES', 'LIMIT', 0, count
);
const players = [];
for (let i = 0; i < results.length; i += 2) {
players.push({
userId: results[i],
score: parseInt(results[i + 1]),
rank: players.length + 1,
});
}
return players;
}
async function getUserRank(userId) {
const rank = await redis.zrevrank('leaderboard', userId);
return rank !== null ? rank + 1 : null; // 1-indexed
}
Python Version
import redis
import json
from datetime import timedelta
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
# Cache function decorator
def cached(ttl_seconds=300):
def decorator(func):
def wrapper(*args, **kwargs):
cache_key = f"{func.__name__}:{args}:{kwargs}"
cached_value = r.get(cache_key)
if cached_value:
return json.loads(cached_value)
result = func(*args, **kwargs)
r.setex(cache_key, ttl_seconds, json.dumps(result))
return result
return wrapper
return decorator
@cached(ttl_seconds=60)
def get_user(user_id):
# This expensive call is only made once per minute
return db.query(f"SELECT * FROM users WHERE id = {user_id}")
Redis Data Types Cheat Sheet
| Type | Use Case | Key Commands |
|---|---|---|
| String | Cache, counters, flags | GET, SET, INCR, EXPIRE |
| Hash | User profiles, configs | HGET, HSET, HMGET |
| List | Queues, activity feeds | LPUSH, RPOP, LRANGE |
| Set | Tags, unique visitors | SADD, SMEMBERS, SINTER |
| Sorted Set | Leaderboards, priority queues | ZADD, ZRANGE, ZREVRANK |
| Stream | Event logs, message queues | XADD, XREAD, XGROUP |
Production Tips
✅ Always set TTLs — memory is finite, stale data is dangerous
✅ Use key namespacing — user:123:profile, not just 123
✅ Enable persistence — RDB snapshots or AOF for durability
✅ Monitor memory — redis-cli INFO memory
✅ Use connection pooling — don't create a new connection per request
⚠️ Don't store sensitive data unencrypted — Redis is typically not encrypted at rest
When Not to Use Redis
- Long-term data storage → Use PostgreSQL/MongoDB
- Complex queries → Your relational DB handles this better
- Large files/blobs → Use S3 or filesystem
Redis shines as a complement to, not replacement for, your primary database.
With these five patterns, you'll solve 90% of the performance and real-time problems you'll face building production apps in 2026.
Start with caching — it's the highest ROI change you can make to a slow app.
Building projects and tools for developers and freelancers. Resources at guittet.gumroad.com — including the Freelancer OS Notion template and AI prompt packs.
Top comments (0)