# Channels & Routing (/learn/concepts/channels-and-routing)



Think of a channel like the address on an envelope. You do not hand a letter directly to a person — you drop it in the mail with an address, and the postal system delivers it to whoever picks up mail at that address. Senders and receivers never need to know about each other; they only need to agree on the address.

A **channel** is that address: a named destination that a broker uses to route messages. Publishers send to a channel name; subscribers express interest in a channel name. The broker connects the two. This indirection is what makes messaging *loosely coupled* — you can add, remove, or move services without either side changing the other's code.

## Channels — the idea [#channels--the-idea]

A channel is just a string name, chosen by you. Publishers attach that name to each message; the broker matches it against the names subscribers asked for and delivers accordingly. Nothing is hard-wired — the channel is created the moment something uses it.

Good channel names follow a **hierarchy**, read left to right from broad to specific, with a separator between each level. A common convention is `{domain}.{entity}.{action}`:

```text
orders.created
orders.updated
orders.us-east.created
payments.completed
inventory.reserved
```

That hierarchy is not decoration. It is what makes the next idea — wildcards — possible.

<Mermaid
  chart="graph LR
  PUB1[&#x22;Orders Service&#x22;]
  PUB2[&#x22;Payments Service&#x22;]

  subgraph KubeMQ
    C1{{&#x22;orders.created&#x22;}}
    C2{{&#x22;orders.updated&#x22;}}
    C3{{&#x22;payments.completed&#x22;}}
  end

  SUB1[&#x22;Orders Monitor&#x22;]
  SUB2[&#x22;Payments Ledger&#x22;]

  PUB1 -- publish --> C1
  PUB1 -- publish --> C2
  PUB2 -- publish --> C3
  C1 --> SUB1
  C2 --> SUB1
  C3 --> SUB2

  class C1,C2,C3 events
  class PUB1,PUB2,SUB1,SUB2 client"
/>

*Channels are named destinations; the broker matches a publisher's channel name to the subscribers that asked for it.*

## Wildcards — subscribing to a pattern [#wildcards--subscribing-to-a-pattern]

Naming channels one by one works until you have dozens of them. A monitoring service that needs *every* order event would have to subscribe to `orders.created`, `orders.updated`, `orders.shipped`, and remember to add a new subscription every time someone invents `orders.cancelled`.

A **wildcard subscription** solves this: instead of naming exact channels, the subscriber names a *pattern*, and the broker delivers every message whose channel matches. The hierarchy makes the pattern meaningful — each level can be matched broadly or exactly.

Two wildcard tokens are common, and KubeMQ uses both:

| Token | Matches            | Example                                                            |
| ----- | ------------------ | ------------------------------------------------------------------ |
| `*`   | exactly one level  | `orders.*` matches `orders.created`, not `orders.us-east.created`  |
| `>`   | one or more levels | `orders.>` matches `orders.created` *and* `orders.us-east.created` |

A standalone `>` subscribes to everything — a firehose for audit or debugging.

<Mermaid
  chart="graph LR
  PUB[&#x22;Orders Service&#x22;]

  subgraph KubeMQ
    C1{{&#x22;orders.created&#x22;}}
    C2{{&#x22;orders.updated&#x22;}}
    C3{{&#x22;orders.us-east.created&#x22;}}
  end

  W1[&#x22;Orders Monitor<br/>subscribes orders.*&#x22;]
  W2[&#x22;Global Auditor<br/>subscribes &gt;&#x22;]

  PUB -- publish --> C1
  PUB -- publish --> C2
  PUB -- publish --> C3

  C1 --> W1
  C2 --> W1
  C1 --> W2
  C2 --> W2
  C3 --> W2
  C3 -. &#x22;no match for orders.*&#x22; .-> W1

  class C1,C2,C3 events
  class PUB,W1 client
  class W2 client"
/>

*One pattern subscription captures many channels: `orders.*` matches single-level order events, while `>` captures everything.*

<Callout type="warn">
  **Pitfall:** wildcards belong to *subscriptions*, not *publishes*. A publisher must always send to a concrete channel name — `orders.created`, never `orders.*`. The `*` and `>` characters are illegal in a publish channel.
</Callout>

## Routing — one publish, many channels [#routing--one-publish-many-channels]

Wildcards let one subscriber listen to many channels. **Multicast routing** is the mirror image: it lets one *publish* reach many channels at once, without the publisher looping or opening multiple connections.

The publisher encodes a list of targets into the channel name, and the broker fans the message out to each. This is how you tee a single business event to several consumers with different needs — a live feed *and* a durable copy *and* a work queue — from one call.

<Mermaid
  chart="graph LR
  PUB[&#x22;Orders Service<br/>publishes once&#x22;]
  R{&#x22;Router&#x22;}

  subgraph KubeMQ
    EV{{&#x22;order-live<br/>(events)&#x22;}}
    ST{{&#x22;order-archive<br/>(events store)&#x22;}}
    QU[[&#x22;order-fulfilment<br/>(queue)&#x22;]]
  end

  LIVE[&#x22;Live Dashboard&#x22;]
  AUDIT[&#x22;Audit / Replay&#x22;]
  WORKER[&#x22;Fulfilment Worker&#x22;]

  PUB -- &#x22;one message&#x22; --> R
  R --> EV
  R --> ST
  R --> QU
  EV --> LIVE
  ST --> AUDIT
  QU --> WORKER

  class EV events
  class ST store
  class QU queue
  class R broker
  class PUB,LIVE,AUDIT,WORKER client"
/>

*A single publish fans out to channels of different types at once — a real-time feed, a durable store, and a reliable work queue.*

## Precise definition [#precise-definition]

* **Channel** — a named destination string. Created on first use, addressed by publishers and subscribers; the unit the broker routes on.
* **Hierarchical naming** — a dot-separated convention (`domain.entity.action`) that gives channels structure so patterns can match levels.
* **Wildcard subscription** — a subscription whose channel is a *pattern* using `*` (one level) or `>` (one or more levels). The broker delivers every message whose channel matches.
* **Multicast routing** — a single publish addressed to multiple channels at once, encoded in the channel string; the broker delivers a copy to each target.

## Trade-offs [#trade-offs]

| When it helps                                                                                        | When it bites                                                                                                             |
| ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| A consumer needs a whole category of channels — one `orders.>` beats a dozen explicit subscriptions. | A too-broad pattern (`>`) hauls in traffic you do not need, wasting bandwidth and processing.                             |
| You want to tee one event to several patterns (live + durable + queue) without publisher-side loops. | Routing to many targets multiplies broker work per publish; very wide fan-outs add latency.                               |
| A naming hierarchy lets new channels appear without changing subscribers.                            | Inconsistent naming breaks wildcards — `order.created` and `orders.created` will not match the same pattern.              |
| Routing keeps publishers simple — they do not track who consumes what.                               | Routing hides destinations in a string; an inspectable, documented naming scheme is essential to avoid surprise delivery. |

## In KubeMQ [#in-kubemq]

KubeMQ channels are exactly the named destinations above — a plain string you choose, created on first use. **Wildcard subscriptions** are supported for **Events** (Pub/Sub): subscribe to `orders.*` or `>` and the broker matches every event channel against your pattern. **Multicast routing** is encoded directly in the channel string: `;` separates targets and a `type:` prefix selects the pattern.

| Routing string                                 | Effect                                         |
| ---------------------------------------------- | ---------------------------------------------- |
| `events:order-live;events_store:order-archive` | one publish → a live feed *and* a durable copy |
| `events:notify;queues:order-fulfilment`        | broadcast *and* a reliable work queue          |

The snippet below is the canonical wildcard subscribe from the Events tutorial — one subscription to `orders.*` captures every single-level order channel.

<Tabs groupId="language" items="['Go', 'Python', 'Node.js', 'Java', 'C#', 'Kotlin', 'C++', 'Rust', 'Ruby', 'Elixir']">
  <Tab value="Go">
    ```go title="orders_monitor.go"
    sub, err := client.SubscribeToEvents(ctx, "orders.*", "",
        kubemq.WithOnEvent(func(event *kubemq.Event) {
            fmt.Printf("[Orders Monitor] channel=%s body=%s\n",
                event.Channel, string(event.Body))
        }),
        kubemq.WithOnError(func(err error) {
            log.Println("Error:", err)
        }),
    )
    ```
  </Tab>

  <Tab value="Python">
    ```python title="orders_monitor.py"
    client.subscribe_to_events(
        subscription=EventsSubscription(
            channel="orders.*",
            on_receive_event_callback=lambda e: print(
                f"[Orders Monitor] channel={e.channel} body={e.body.decode()}"
            ),
            on_error_callback=lambda e: print(f"Error: {e}"),
        ),
        cancel=CancellationToken(),
    )
    ```
  </Tab>

  <Tab value="Node.js">
    ```javascript title="orders_monitor.js"
    client.subscribeToEvents({
      channel: "orders.*",
      onEvent: (msg) =>
        console.log(
          `[Orders Monitor] channel=${msg.channel} body=${Buffer.from(msg.body).toString()}`
        ),
      onError: (err) => console.error("Error:", err.message),
    });
    ```
  </Tab>

  <Tab value="Java">
    ```java title="OrdersMonitor.java"
    client.subscribeToEvents(EventsSubscription.builder()
        .channel("orders.*")
        .onReceiveEventCallback(event ->
            System.out.printf("[Orders Monitor] channel=%s body=%s%n",
                event.getChannel(), new String(event.getBody())))
        .onErrorCallback(err ->
            System.err.println("Error: " + err.getMessage()))
        .build());
    ```
  </Tab>

  <Tab value="C#">
    ```csharp title="OrdersMonitor.cs"
    await foreach (var msg in client.SubscribeToEventsAsync(
        new EventsSubscription { Channel = "orders.*" }))
    {
        Console.WriteLine($"[Orders Monitor] channel={msg.Channel} "
            + $"body={Encoding.UTF8.GetString(msg.Body.Span)}");
    }
    ```
  </Tab>

  <Tab value="Kotlin">
    ```kotlin title="OrdersMonitor.kt"
    client.subscribeToEvents(
        channel = "orders.*",
        onEvent = { event ->
            println("[Orders Monitor] channel=${event.channel} body=${String(event.body)}")
        },
        onError = { err -> System.err.println("Error: ${err.message}") }
    )
    ```
  </Tab>

  <Tab value="C++">
    ```cpp title="orders_monitor.cpp"
    client.subscribeToEvents("orders.*", "",
        [](const kubemq::Event& event) {
            std::cout << "[Orders Monitor] channel=" << event.channel
                      << " body=" << event.body << std::endl;
        },
        [](const std::string& err) {
            std::cerr << "Error: " << err << std::endl;
        }
    );
    ```
  </Tab>

  <Tab value="Rust">
    ```rust title="orders_monitor.rs"
    // A single wildcard subscription matches every channel under the pattern.
    let sub = client
        .subscribe_to_events(
            "orders.*",
            "",
            |event| {
                Box::pin(async move {
                    println!(
                        "[Orders Monitor] channel={}, body={}",
                        event.channel,
                        String::from_utf8_lossy(&event.body)
                    );
                })
            },
            None,
        )
        .await?;
    ```
  </Tab>

  <Tab value="Ruby">
    ```ruby title="orders_monitor.rb"
    cancel = KubeMQ::CancellationToken.new

    sub = KubeMQ::PubSub::EventsSubscription.new(channel: "orders.*")
    client.subscribe_to_events(sub, cancellation_token: cancel,
      on_error: ->(e) { puts "Error: #{e.message}" }) do |event|
      puts "[Orders Monitor] channel=#{event.channel} body=#{event.body}"
    end
    ```
  </Tab>

  <Tab value="Elixir">
    ```elixir title="orders_monitor.exs"
    {:ok, sub} =
      KubeMQ.Client.subscribe_to_events(client, "orders.*",
        on_event: fn event ->
          IO.puts("[Orders Monitor] channel=#{event.channel} body=#{event.body}")
        end
      )
    ```
  </Tab>
</Tabs>

<Callout type="info">
  **In KubeMQ:** wildcard subscriptions are an **Events** feature. Events Store, Queues, and RPC use exact channel names — they do not match `*` or `>` patterns. Multicast routing, by contrast, works across patterns: one routing string can tee an event into Events, Events Store, and Queues at the same time.
</Callout>

### How KubeMQ does this → [#how-kubemq-does-this-]

<Cards>
  <Card title="Channel Routing" href="/learn/guides/channel-routing" description="The hands-on guide to multicast routing syntax — publish once to many channels and patterns." />

  <Card title="Channel Management" href="/learn/guides/channel-management" description="Inspect, list, and manage channels across patterns." />

  <Card title="Wildcard Subscriptions" href="/learn/events/tutorials/wildcard-subscriptions" description="Step-by-step: subscribe to orders.* and > with the Events SDK." />

  <Card title="Multicast Events" href="/learn/events/tutorials/multicast" description="Fan one publish out to multiple channels from a single call." />

  <Card title="Events — Real-Time Pub/Sub" href="/learn/events" description="The pattern where channels and wildcards live." />
</Cards>
