Redis for Backend: Cache, Sessions, and Pub/Sub
Redis is often introduced as “a fast cache.” That description is accurate but incomplete. Redis is an in-memory data store with several useful data structures, optional persistence, expiration controls, and replication features. It can reduce database load, hold session state, coordinate short-lived work, and distribute real-time notifications. Each use case has different failure semantics, so treating Redis as a generic bucket of data creates production surprises.
When Redis is the right tool
Redis is most valuable when the data is read frequently, can be reconstructed, or has a naturally short lifetime. Examples include product pages, permission lookups, rate-limit counters, session records, and the latest presence state for a chat room.
It should not quietly become the only source of truth for orders, balances, or any data whose loss would be unacceptable. Even with persistence enabled, Redis is usually operated for speed first. Keep durable business records in the database designed to own them, then use Redis to make common reads and coordination cheaper.
Caching patterns that survive production
The most common pattern is cache-aside: the application checks Redis, reads the database on a miss, then stores the result with an expiry.
const key = `product:${productId}`;
const cached = await redis.get(key);
if (cached) return JSON.parse(cached);
const product = await db.product.findById(productId);
await redis.set(key, JSON.stringify(product), { EX: 300 });
return product;
An expiry is not optional. Without one, stale values accumulate forever. Pick a TTL from the acceptable staleness of the feature, then invalidate deliberately after writes when users need to see an update immediately. For example, deleting product:42 after a product edit is simpler and safer than trying to update every cached representation.
Protect the database from a cache stampede: when a popular key expires, many requests may rebuild it at once. Add randomized TTL jitter, use a short lock for expensive rebuilds, or serve a slightly stale value while one worker refreshes it. Also cache only successful, safe results; caching an authorization failure or a transient error can lock users out longer than intended.
Sessions and authentication
Redis is a good session store when application instances are stateless. Store an opaque session ID in a secure, HTTP-only cookie and put the server-side session document in Redis with a TTL that matches the session policy.
Keep the session small: user ID, session version, issued time, and only the claims needed on every request. Do not place passwords, access tokens, or large profiles in it. Rotate the session ID after login and privilege changes, set Secure, HttpOnly, and appropriate SameSite cookie flags, and delete the Redis key on logout. If a user must be logged out everywhere, use a session version or an indexed list of active session IDs rather than scanning keys.
Pub/Sub is not a durable queue
With Redis Pub/Sub, publishers send a message to a channel and currently connected subscribers receive it. It is useful for “refresh this screen” events, local WebSocket fan-out, or cache invalidation hints. A disconnected subscriber misses the message, and a slow subscriber has no durable backlog.
For work that must be processed eventually—email delivery, payment reconciliation, image conversion—use a durable queue or stream with acknowledgements, retries, dead-letter handling, and idempotent consumers. Redis Streams can provide consumer groups and retained messages, but they still need explicit operations and monitoring.
Memory, eviction, and persistence
Redis keeps the working set in memory. Configure maxmemory and an eviction policy intentionally. allkeys-lru is reasonable for a pure cache; noeviction is safer when losing a key would break a workflow, because writes fail visibly instead of silently discarding data. Never mix critical queues and disposable cache data in the same instance unless you fully understand the eviction consequences.
RDB snapshots provide compact point-in-time persistence. AOF records write operations and can reduce data loss between snapshots at a higher I/O cost. Replication improves availability, but a failover can still lose recently acknowledged writes depending on configuration. Test restore and failover procedures; a backup setting is not a recovery plan.
Keys, observability, and safety
Use predictable, namespaced keys such as app:session:<id> and app:rate-limit:<userId>:<minute>. Avoid KEYS * in production because it blocks the server on large keyspaces; use SCAN for maintenance tasks. Track memory use, hit rate, evictions, command latency, connected clients, replication lag, and rejected writes. Alert on evictions for stateful workloads.
Treat Redis credentials like database credentials, use TLS when traffic crosses trusted network boundaries, and restrict network access. Commands are powerful: an exposed Redis instance can become a data-loss incident.
Practical checklist
- Define whether each key is cache, session, coordination state, or durable work.
- Set a TTL, invalidation rule, and owner for every non-durable key.
- Test cache misses, stampedes, eviction, restart, and Redis unavailability.
- Make consumers idempotent and choose a durable mechanism for must-deliver work.
- Monitor memory, eviction, latency, and hit rate before the service is under pressure.
Conclusion
Redis rewards precise use. Use it as an acceleration layer and a short-lived coordination tool, with explicit expiry and failure behavior. When its data model matches the problem, it makes systems faster and simpler; when it is asked to be an unplanned primary database, it makes failures harder to reason about.
Related Articles
Keep reading within the same topic.
Connection Pooling: Maximizing Database Performance
Understand database connection pooling, how to size it, diagnose saturation, and avoid common serverless and transaction pitfalls.
NoSQL vs Relational: Choosing the Right Database for Your Project
A practical framework for choosing relational or NoSQL databases from data shape, queries, consistency, and operational needs.
GraphQL API Guide: Schema, Query, and Mutation Basics
Learn GraphQL API basics through schema design, queries, mutations, resolvers, error handling, and practical patterns for app data.
Database Indexing Strategy: B-Trees, Hash Indexes, and More
Learn how to choose, validate, and maintain database indexes without slowing down writes or guessing at performance.