Redis is an in-memory data structure store that serves as a cache, session store, message queue, rate limiter, and pub/sub broker. It is not just a cache, and understanding its full range of capabilities will make you a significantly more effective developer.
What Redis Actually Is
Redis stands for Remote Dictionary Server. At its core, it is a key-value store that lives entirely in memory, making reads and writes orders of magnitude faster than any disk-based database. But unlike Memcached (the other in-memory cache), Redis supports rich data structures: strings, hashes, lists, sets, sorted sets, streams, and more. Each data structure comes with its own set of atomic operations, which makes Redis useful for problems far beyond simple caching.
Use Case 1: Caching (The Obvious One)
Caching is how most developers encounter Redis, and it is a genuinely excellent use case. The pattern is simple: before hitting your database, check Redis for a cached result. If it exists (a cache hit), return it immediately. If not (a cache miss), query the database, store the result in Redis with a TTL (time to live), and return it.
const cached = await redis.get(`user:${userId}`)
if (cached) return JSON.parse(cached)
const user = await db.collection('users').findOne({ _id: userId })
await redis.setex(`user:${userId}`, 3600, JSON.stringify(user)) // 1 hour TTL
return user
The key decisions in caching are: what to cache, how long to cache it, and how to invalidate it when the underlying data changes. Cache invalidation is one of the famously hard problems in computer science. Simple strategies: always invalidate on write (delete the cache key when the underlying record is updated), or use short TTLs and accept occasional stale data.
Redis vs Postgres for caching: Redis operates in microseconds, Postgres in milliseconds. For frequently read data, this difference compounds. But Redis is one more service to manage. If your query is fast enough with a Postgres index, adding Redis is unnecessary complexity. Start without it.
Use Case 2: Session Storage
HTTP is stateless, so sessions require storing state somewhere. Options include: cookies (simple, but limited size and security considerations), database (works, but adds latency to every authenticated request), and Redis (fast, TTL-native, and shared across all app instances).
Redis is excellent for session storage because it natively supports expiration (a session TTL of 24 hours is just SETEX session:token 86400 data) and because horizontal scaling is trivial: multiple app instances all hit the same Redis instance, so sessions are shared without any coordination logic.
Use Case 3: Rate Limiting
Rate limiting is where Redis's atomic operations shine. The pattern for a simple rate limiter: increment a counter per user per time window, and reject requests that exceed the limit.
const key = `rate:${userId}:${Math.floor(Date.now() / 60000)}` // per-minute window
const count = await redis.incr(key)
if (count === 1) await redis.expire(key, 60) // set TTL on first increment
if (count > 100) throw new Error('Rate limit exceeded')
The INCR command is atomic, meaning concurrent requests from the same user will not race and produce an incorrect count. This is critical for rate limiting correctness.
Sorted sets enable more sophisticated rate limiters (sliding window algorithms) where you store timestamps of requests and count requests within the last N seconds. This avoids the "boundary problem" of fixed windows (where a user can send 2x the limit by straddling the window boundary).
Use Case 4: Queues (BullMQ)
Redis Lists support push and pop operations that are perfect for job queues. BullMQ is the most popular Node.js library built on top of Redis for job queue management.
With BullMQ, you push jobs onto a queue (stored in Redis) and worker processes consume them. Features include: job prioritization, delayed jobs (run this job in 10 minutes), retry logic with exponential backoff, concurrency control, job progress tracking, and job events.
This is how you should handle any work that does not need to happen synchronously in an HTTP request: sending emails, processing images, syncing data to third-party APIs, running reports. The request enqueues a job and returns immediately. Workers process jobs in the background.
Use Case 5: Pub/Sub for Real-Time Features
Redis Pub/Sub lets one process publish messages to a channel and any number of subscribers receive them in real time. This is useful for broadcasting events across multiple app instances.
For example: when a user sends a chat message, the API server publishes to a Redis channel. All Socket.IO server instances subscribed to that channel receive the message and push it to connected clients. Without Redis Pub/Sub, a message received by server instance A would not reach users connected to instance B.
Note: for this specific Socket.IO use case, the socket.io-redis adapter handles the pub/sub automatically.
Use Case 6: Distributed Locks
When multiple servers might try to perform the same operation concurrently (running a cron job, processing a webhook), a distributed lock prevents double execution. Redis's SET key value NX PX timeout command atomically sets a key only if it does not exist, providing a reliable distributed mutex.
Redlock is a well-known algorithm and library for distributed locking with Redis that handles failure cases like the lock holder crashing before releasing the lock.
Redis vs Memcached
Memcached is simpler (strings only) and slightly faster for basic caching due to lower overhead. Redis is richer (multiple data structures), supports persistence, pub/sub, replication, and clustering. For new projects in 2026, choose Redis. Memcached's remaining use cases are niche.
Upstash: Serverless Redis
Traditional Redis requires a persistent connection and does not work in serverless or edge environments where each function invocation is stateless. Upstash is a serverless Redis provider that accepts HTTP requests, making it compatible with Vercel Edge Functions, Cloudflare Workers, and AWS Lambda.
The trade-off: HTTP adds latency versus a persistent TCP connection. Upstash is appropriate for serverless-first architectures where you cannot maintain a persistent Redis connection. For traditional server environments, a standard Redis instance (self-hosted or via Redis Cloud, Upstash Serverless, or Render Redis) is fine.
Deployment Options
- Self-hosted: Docker or system package, lowest cost, you manage it
- Redis Cloud: managed Redis from Redis Labs, free 30MB tier
- Upstash: serverless/HTTP Redis, generous free tier, usage-based pricing
- Render: managed Redis add-on, easiest if already on Render
- AWS ElastiCache: managed Redis for AWS-heavy stacks, expensive
Keep Reading
- Postgres Guide for Developers — when to use Postgres instead of Redis for storage problems
- MongoDB Guide for Developers — another non-relational database option
- Grafana and Prometheus Monitoring Guide — monitoring your Redis instance in production
Pristren builds AI-powered software for teams. Zlyqor is our all-in-one workspace — chat, projects, time tracking, AI meeting summaries, and invoicing — in one tool. Try it free.