Pub/Sub is Redis’s built-in messaging system. Publishers shout into a channel, subscribers listening on that channel receive the message. No queue, no persistence — if you’re not listening when a message is published, you miss it forever.
In simple language: it’s like a radio broadcast. The DJ plays a song. If your radio is on, you hear it. If it’s off, tough luck — there’s no replay.
Why use it?
Real-time fanout where missing a message is acceptable:
- Cache invalidation across app servers (“user:123 changed, drop your cached copy”)
- Live notifications (someone liked your post)
- Chat rooms with no history requirement
- Triggering refreshes on a dashboard
Pub/Sub trades durability for simplicity and speed.
The commands
# Terminal 1 - subscriber
SUBSCRIBE news.tech news.sports
# Terminal 2 - publisher
PUBLISH news.tech "Redis 8 released"
# returns the number of subscribers that received it
Pattern subscription with PSUBSCRIBE uses glob-style wildcards:
PSUBSCRIBE news.* # matches news.tech, news.sports, anything
PSUBSCRIBE order.*.paid # matches order.123.paid
Fanout in one picture
The catch: fire-and-forget
Redis Pub/Sub has at-most-once delivery:
- No persistence — messages live only in memory during delivery
- No acknowledgments — Redis doesn’t care if you actually processed it
- No replay — disconnected subscribers can’t catch up
- Slow subscribers get disconnected (Redis won’t buffer indefinitely)
If your subscriber crashes mid-message, that message is gone.
Pub/Sub vs Streams
Streams (XADD/XREAD) were added precisely because Pub/Sub couldn’t handle durable messaging.
| Feature | Pub/Sub | Streams |
|---|---|---|
| Persistence | No | Yes (in-memory + AOF/RDB) |
| Replay | No | Yes, by ID |
| Consumer groups | No | Yes (Kafka-like) |
| Acknowledgments | No | Yes (XACK) |
| Delivery | At-most-once | At-least-once |
| Use case | Live fanout | Event sourcing, work queues |
Rule of thumb: if missing a message is a bug, use Streams. If missing a message is fine, Pub/Sub is simpler and faster.
Real-world example: cache invalidation
// Publisher (after DB write)
await db.update("users", { id: 123, name: "Manish" });
await redis.publish("cache.invalidate", "user:123");
// Subscriber (every app server)
sub.subscribe("cache.invalidate");
sub.on("message", (channel, key) => {
localCache.delete(key);
});
Every app server clears its in-memory cache the moment the DB changes. If a server happens to be restarting and misses the message, no big deal — its cache is empty anyway.
Gotchas
- Subscribed clients can’t issue normal commands (the connection is in subscribe mode). Use a separate connection for publishing.
PSUBSCRIBEis slower thanSUBSCRIBE— Redis runs glob matching per channel per pattern.- In Cluster mode, regular Pub/Sub broadcasts cluster-wide. Sharded Pub/Sub (
SSUBSCRIBE, Redis 7+) scopes channels to shards for better scalability.