Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Subscribe to channels in Redis

Learn how to subscribe to channels in Redis for real-time messaging. This hands-on tutorial covers the SUBSCRIBE command, channel patterns, and practical examples for building pub/sub systems.

Focus: subscribe to channels in redis

Sponsored

You've built a Redis-backed application that stores and retrieves data, but what if you need to notify other parts of your system instantly when something changes? Polling the database every few seconds is inefficient and slow. Redis's pub/sub (publish/subscribe) model solves this by letting you subscribe to channels and receive messages in real-time, enabling everything from live chat updates to event-driven microservices.

The problem this lesson solves

Traditional request-response patterns force your application to constantly ask "is there new data?" This burns CPU, increases latency, and creates unnecessary load on both your app and Redis. Consider a stock ticker that needs to display price changes to hundreds of users — polling every second would be wasteful and still miss updates between polls.

Redis pub/sub eliminates polling entirely. When you subscribe to channels in Redis, your client receives messages the moment they're published. This "fire and forget" pattern is perfect for:

  • Real-time notifications — new user signups, payment confirmations
  • Live dashboards — pushing metrics to connected browsers
  • Inter-service communication — microservices reacting to events without tight coupling

The key insight: subscribers never ask for data. They listen. Publishers never know who's listening. This decoupling makes your system more scalable and responsive.

Core concept / mental model

Think of Redis pub/sub like a radio broadcast. The channel is the radio frequency. A publisher is the radio station — it transmits on a frequency without knowing who's listening. A subscriber is someone with a radio tuned to that frequency — they hear the broadcast when it happens, but can't rewind or ask for past content.

Pro tip: Unlike a message queue, Redis pub/sub has no memory. If you're not subscribed when a message is published, you'll never receive it. This is by design — it's for real-time streams, not guaranteed delivery.

Key definitions:

  • Channel: A string name (e.g., notifications, orders:new) that organizes messages
  • Publisher: A client that sends a message to a channel using PUBLISH
  • Subscriber: A client that receives messages from a channel after using SUBSCRIBE
  • Message: The payload — always a string in Redis pub/sub

How it works step by step

Follow this sequence to understand the lifecycle of a pub/sub message:

  1. A subscriber client connects to Redis and issues the SUBSCRIBE command with one or more channel names.
  2. Redis marks the client as a subscriber — the connection enters "subscriber mode" and can no longer issue regular commands like GET or SET.
  3. A publisher client sends a PUBLISH command with a channel name and a message.
  4. Redis looks up all subscribers for that channel and forwards the message to each one.
  5. Each subscriber receives the message as a three-element array: the message type (message), the channel name, and the actual payload.

When you subscribe to channels in Redis, the connection becomes dedicated to receiving messages. You can't interleave regular commands — the only allowed commands are SUBSCRIBE, UNSUBSCRIBE, PSUBSCRIBE (pattern-based), and QUIT.

# In terminal 1 — subscriber
redis-cli SUBSCRIBE orders:new
# Output:
# 1) "subscribe"
# 2) "orders:new"
# 3) (integer) 1

# In terminal 2 — publisher
redis-cli PUBLISH orders:new "order-101: paid"
# Output: (integer) 1  ← one subscriber received the message

# Back in terminal 1, the subscriber sees:
# 1) "message"
# 2) "orders:new"
# 3) "order-101: paid"

Subscribers can also unsubscribe:

redis-cli UNSUBSCRIBE orders:new
# Output:
# 1) "unsubscribe"
# 2) "orders:new"
# 3) (integer) 0  ← no longer subscribed to any channels

Hands-on walkthrough

Let's build a practical example: a Python application that monitors new user registrations and sends a welcome notification. We'll start with a publisher script and a subscriber script.

Publisher — publish_user.py

import redis
import json
import time

# Connect to Redis
client = redis.Redis(host='localhost', port=6379, decode_responses=True)

# Simulate new user registrations
def register_user(user_id, username):
    event = {
        'user_id': user_id,
        'username': username,
        'timestamp': time.time()
    }
    # Publish the event to the 'users:new' channel
    result = client.publish('users:new', json.dumps(event))
    print(f"Published event for {username}. Subscribers reached: {result}")

# Simulate a few registrations
register_user(101, 'alice')
register_user(102, 'bob')
time.sleep(1)
register_user(103, 'charlie')

Subscriber — subscribe_users.py

import redis
import json

client = redis.Redis(host='localhost', port=6379, decode_responses=True)
pubsub = client.pubsub()

# Subscribe to the 'users:new' channel
pubsub.subscribe('users:new')
print("Subscribed to 'users:new'. Waiting for events...")

# Listen for messages (this blocks)
for message in pubsub.listen():
    if message['type'] == 'message':
        data = json.loads(message['data'])
        print(f"New user registered: {data['username']} (ID: {data['user_id']})")
        # In a real app, you'd send an email, update a dashboard, etc.

Run these in two terminals:

# Terminal 1 — subscriber
python subscribe_users.py
# Output:
# Subscribed to 'users:new'. Waiting for events...

# Terminal 2 — publisher
python publish_user.py
# Output in subscriber terminal:
# New user registered: alice (ID: 101)
# New user registered: bob (ID: 102)
# New user registered: charlie (ID: 103)

Pro tip: The decode_responses=True parameter ensures messages come back as strings instead of bytes, which makes JSON handling much cleaner.

Pattern-based subscriptions with PSUBSCRIBE

You can subscribe to multiple channels using glob-style patterns:

# Subscribe to all order-related channels (orders:new, orders:cancelled, etc.)
pubsub.psubscribe('orders:*')

# This will receive messages from:
# - PUBLISH orders:new "order-201: pending"
# - PUBLISH orders:cancelled "order-101: refunded"
# But NOT from:
# - PUBLISH payments:failed "order-301: declined"

Pattern subscriptions require more CPU on the Redis server because they must match against the channel name. Use them sparingly in high-throughput systems.

Compare options / when to choose what

Not all real-time messaging is the same. Here's how Redis pub/sub stacks up against alternatives:

Feature Redis Pub/Sub Redis Streams Message Queue (e.g., RabbitMQ)
Message persistence None — lost if no subscriber Persistent — can replay Usually persistent
Delivery guarantee At-most-once — if subscriber disconnects, message is lost At-least-once with consumer groups At-least-once or exactly-once
Subscriber state Stateless — just listens Stateful — tracks read position Stateful — acks messages
Scalability Excellent — fan-out to many subscribers Good — consumer groups share load Moderate — depends on broker
Use case Real-time broadcasts, notifications Event sourcing, job queues Reliable task processing

When to use publish/subscribe to channels in Redis:

  • You need fast, simple fan-out to multiple consumers
  • Message loss is acceptable (notifications can be retried via another channel)
  • You want zero overhead — no persistent storage, no ack framework
  • Your subscribers are typically always-on services

When to avoid it:

  • You need guaranteed delivery (use Redis Streams or a message broker)
  • Subscribers connect intermittently (they'll miss messages)
  • You need message ordering across subscriber reconnections (Streams track this)

Troubleshooting & edge cases

Subscriber mode restriction

Once a client issues SUBSCRIBE, it enters subscriber mode. Any attempt to run a non-subscription command will fail:

# Subscriber tries to run GET after subscribing
redis-cli SUBSCRIBE test
redis-cli GET mykey
# Error: Redis is in subscriber mode, cannot execute non-subscription commands

Fix: Use a separate connection for non-subscription work, or call UNSUBSCRIBE first to exit subscriber mode.

Missing messages during reconnection

If your subscriber disconnects and reconnects, any messages published during the gap are lost forever:

# This will miss messages published between disconnection and resubscription
pubsub = client.pubsub()
pubsub.subscribe('important_alerts')

Workaround: Use a heartbeat or health-check channel. Have publishers periodically send a "still alive" message. Better yet, use Redis Streams if you can't tolerate loss.

High memory from slow subscribers

If a subscriber is slow to process messages but fast enough to keep the connection alive, Redis buffers messages in the output buffer. This can consume memory:

# Check memory per client
redis-cli CLIENT LIST
# Look for "omem" field — if very large, the subscriber is falling behind

Mitigation: Increase client-output-buffer-limit for pub/sub clients, or implement backpressure in your subscriber code.

Pattern subscription performance

Using PSUBSCRIBE orders:* with thousands of PUBLISH calls per second can slow down Redis because it must pattern-match each message. A dedicated channel per entity (e.g., orders:101, orders:102) is faster because Redis uses a hash table lookup.

What you learned & what's next

You've mastered how to subscribe to channels in Redis — from the basic SUBSCRIBE command to pattern matching and Python integration. You understand:

  • The fire-and-forget nature of pub/sub and when to use it over queues or streams
  • How to build a publisher and subscriber in Python with the redis-py library
  • The critical difference between subscribe mode and normal mode
  • How to choose between pub/sub, Streams, and external message brokers

You're now ready to build real-time features like live dashboards, notification systems, and event-driven microservices. But pub/sub has a limitation — no history and no replay. The next lesson introduces Redis Streams, which solve exactly that: persistent, replayable message channels with consumer groups for distributed processing. You'll learn how to build a job queue that survives crashes and scales across workers.

Practice challenge: Modify the subscriber example to subscribe to multiple channels (e.g., 'users:new', 'orders:new'). Have it print which channel each message came from. Then try running two subscriber instances and see how many get each message.

Practice recap

Open two terminal windows. In the first, run redis-cli SUBSCRIBE practice to listen. In the second, run redis-cli PUBLISH practice "hello world". Watch the message appear in the first terminal. Then modify the Python subscriber script to handle multiple channels — add orders:new to your subscription and send test messages from a third terminal.

Common mistakes

  • Trying to run GET or SET commands on a connection that's in subscriber mode — you must use a separate connection for non-pub/sub operations
  • Assuming messages persist if no subscriber is active — pub/sub messages are fire-and-forget; use Streams if you need durable delivery
  • Forgetting decode_responses=True in Python, which makes message data appear as bytes instead of strings, breaking JSON parsing
  • Using PSUBSCRIBE with a broad pattern like * on high-traffic channels, causing Redis to waste CPU on pattern matching

Variations

  1. Instead of SUBSCRIBE, use PSUBSCRIBE to match multiple channels with glob patterns (e.g., users:, orders:)
  2. Use the redis-cli --csv flag to output messages as comma-separated values for simple logging or scripting
  3. For async Python applications, try aioredis library which provides async for message in pubsub.listen(): syntax

Real-world use cases

  • A live sports scoreboard pushing point updates to all connected mobile apps using a single scores:live channel
  • A microservices architecture where orders:created triggers inventory updates, email confirmations, and analytics logging
  • A real-time chat application with per-room channels (e.g., rooms:general, rooms:support) sending messages to all participants

Key takeaways

  • Subscribing to channels in Redis uses SUBSCRIBE and PSUBSCRIBE — no polling needed, messages arrive instantly
  • Publishers don't know who's listening; subscribers receive messages only if connected when published
  • Once a connection subscribes, it enters subscriber mode — regular commands like GET are blocked until UNSUBSCRIBE
  • Redis pub/sub has no message persistence or delivery guarantees — use Streams for durable, replayable messaging
  • Pattern subscriptions (PSUBSCRIBE) are powerful but cost CPU on the server; use specific channels for high throughput
  • Python's redis-py library provides pubsub().subscribe() and .listen() — always set decode_responses=True

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.