# Channel Routing (/learn/guides/channel-routing)



<Callout type="info">
  New to channel naming and fan-out? Start with [Channels & Routing](/learn/concepts/channels-and-routing) in Fundamentals to understand how channels and patterns work before applying the routing syntax below.
</Callout>

## Routing Syntax [#routing-syntax]

KubeMQ supports publishing to multiple channels and patterns in a single operation using a routing syntax built into the channel name:

* **`;`** separates multiple channel targets
* **`:`** prefixes the pattern type (`events`, `events_store`, `queues`)

| Syntax                              | Meaning                         |
| ----------------------------------- | ------------------------------- |
| `events:channel-a;events:channel-b` | Two event channels              |
| `events:live;events_store:archive`  | Event + persistent copy         |
| `events:notify;queues:process`      | Broadcast + reliable work queue |
| `events:a;events_store:b;queues:c`  | All three patterns              |

<Callout type="info">
  Routing is transparent to subscribers — each target channel receives the message as if it were published directly.
</Callout>

## Examples [#examples]

### Events + Events Store [#events--events-store]

Publish an order event to a live channel and persist a copy to an archive channel in a single call.

<Tabs groupId="language" items="['Go', 'Python', 'Node.js', 'Java', 'C#', 'Kotlin', 'C++', 'Rust', 'Ruby', 'Elixir']">
  <Tab value="Go">
    ```go title="route_events_store.go"
    package main

    import (
        "context"
        "log"

        "github.com/kubemq-io/kubemq-go/v2"
    )

    func main() {
        ctx := context.Background()
        client, err := kubemq.NewClient(ctx,
            kubemq.WithAddress("localhost", 50000),
            kubemq.WithClientId("order-router"),
        )
        if err != nil {
            log.Fatal(err)
        }
        defer client.Close()

        err = client.SendEvent(ctx, kubemq.NewEvent().
            SetChannel("events:order-live;events_store:order-archive").
            SetMetadata("order.created").
            SetBody([]byte(`{"orderId":"ORD-100","amount":59.99}`)),
        )
        if err != nil {
            log.Fatal(err)
        }
        log.Println("Routed to events + events_store")
    }
    ```
  </Tab>

  <Tab value="Python">
    ```python title="route_events_store.py"
    from kubemq.pubsub import Client as PubSubClient, EventMessage

    client = PubSubClient(address="localhost:50000", client_id="order-router")

    client.send_event(
        EventMessage(
            channel="events:order-live;events_store:order-archive",
            metadata="order.created",
            body=b'{"orderId":"ORD-100","amount":59.99}',
        )
    )
    print("Routed to events + events_store")
    client.close()
    ```
  </Tab>

  <Tab value="Node.js">
    ```javascript title="route_events_store.js"
    const { KubeMQClient } = require("kubemq-js");

    const client = new KubeMQClient({ address: "localhost:50000", clientId: "order-router" });

    await client.sendEvent({
      channel: "events:order-live;events_store:order-archive",
      metadata: "order.created",
      body: Buffer.from('{"orderId":"ORD-100","amount":59.99}'),
    });
    console.log("Routed to events + events_store");
    ```
  </Tab>

  <Tab value="Java">
    ```java title="RouteEventsStore.java"
    PubSubClient client = PubSubClient.builder()
        .address("localhost:50000")
        .clientId("order-router")
        .build();

    client.sendEventsMessage(EventMessage.builder()
        .channel("events:order-live;events_store:order-archive")
        .metadata("order.created")
        .body("{\"orderId\":\"ORD-100\",\"amount\":59.99}".getBytes())
        .build());
    System.out.println("Routed to events + events_store");
    client.close();
    ```
  </Tab>

  <Tab value="C#">
    ```csharp title="RouteEventsStore.cs"
    await using var client = new KubeMQClient(new KubeMQClientOptions
    {
        Address = "localhost:50000",
        ClientId = "order-router"
    });
    await client.ConnectAsync();

    await client.SendEventAsync(new EventMessage
    {
        Channel = "events:order-live;events_store:order-archive",
        Metadata = "order.created",
        Body = Encoding.UTF8.GetBytes("{\"orderId\":\"ORD-100\",\"amount\":59.99}"),
    });
    Console.WriteLine("Routed to events + events_store");
    ```
  </Tab>

  <Tab value="Kotlin">
    ```kotlin title="RouteEventsStore.kt"
    val client = PubSubClient("localhost:50000")

    client.sendEvent(EventMessage(
        channel = "events:order-live;events_store:order-archive",
        metadata = "order.created",
        body = """{"orderId":"ORD-100","amount":59.99}""".toByteArray(),
    ))
    println("Routed to events + events_store")
    client.close()
    ```
  </Tab>

  <Tab value="C++">
    ```cpp title="route_events_store.cpp"
    #include <kubemq/client.h>
    #include <iostream>

    auto client = kubemq::PubSubClient("localhost:50000");

    kubemq::EventMessage event;
    event.channel = "events:order-live;events_store:order-archive";
    event.metadata = "order.created";
    event.body = R"({"orderId":"ORD-100","amount":59.99})";

    client.sendEvent(event);
    std::cout << "Routed to events + events_store" << std::endl;
    ```
  </Tab>

  <Tab value="Rust">
    ```rust title="route_events_store.rs"
    use kubemq::prelude::*;
    use kubemq::EventBuilder;

    #[tokio::main]
    async fn main() -> kubemq::Result<()> {
        let client = KubemqClient::builder()
            .host("localhost")
            .port(50000)
            .client_id("order-router")
            .build()
            .await?;

        let event = EventBuilder::new()
            .channel("events:order-live;events_store:order-archive")
            .metadata("order.created")
            .body(br#"{"orderId":"ORD-100","amount":59.99}"#.to_vec())
            .build();

        client.send_event(event).await?;
        println!("Routed to events + events_store");

        client.close().await?;
        Ok(())
    }
    ```
  </Tab>

  <Tab value="Ruby">
    ```ruby title="route_events_store.rb"
    require 'kubemq'

    client = KubeMQ::PubSubClient.new(address: 'localhost:50000', client_id: 'order-router')

    msg = KubeMQ::PubSub::EventMessage.new(
      channel: 'events:order-live;events_store:order-archive',
      metadata: 'order.created',
      body: '{"orderId":"ORD-100","amount":59.99}'
    )
    client.send_event(msg)
    puts 'Routed to events + events_store'
    client.close
    ```
  </Tab>

  <Tab value="Elixir">
    ```elixir title="route_events_store.exs"
    {:ok, client} = KubeMQ.Client.start_link(address: "localhost:50000", client_id: "order-router")

    event = KubeMQ.Event.new(
      channel: "events:order-live;events_store:order-archive",
      metadata: "order.created",
      body: ~s({"orderId":"ORD-100","amount":59.99})
    )

    :ok = KubeMQ.Client.send_event(client, event)
    IO.puts("Routed to events + events_store")
    KubeMQ.Client.close(client)
    ```
  </Tab>
</Tabs>

### Events + Queue [#events--queue]

Broadcast an event for real-time subscribers and queue a copy for reliable processing.

<Tabs groupId="language" items="['Go', 'Python', 'Node.js', 'Java', 'C#', 'Kotlin', 'C++', 'Rust', 'Ruby', 'Elixir']">
  <Tab value="Go">
    ```go title="route_events_queue.go"
    err = client.SendEvent(ctx, kubemq.NewEvent().
        SetChannel("events:order-notify;queues:order-process").
        SetMetadata("order.created").
        SetBody([]byte(`{"orderId":"ORD-200","amount":129.00}`)),
    )
    ```
  </Tab>

  <Tab value="Python">
    ```python title="route_events_queue.py"
    client.send_event(
        EventMessage(
            channel="events:order-notify;queues:order-process",
            metadata="order.created",
            body=b'{"orderId":"ORD-200","amount":129.00}',
        )
    )
    ```
  </Tab>

  <Tab value="Node.js">
    ```javascript title="route_events_queue.js"
    await client.sendEvent({
      channel: "events:order-notify;queues:order-process",
      metadata: "order.created",
      body: Buffer.from('{"orderId":"ORD-200","amount":129.00}'),
    });
    ```
  </Tab>

  <Tab value="Java">
    ```java title="RouteEventsQueue.java"
    client.sendEventsMessage(EventMessage.builder()
        .channel("events:order-notify;queues:order-process")
        .metadata("order.created")
        .body("{\"orderId\":\"ORD-200\",\"amount\":129.00}".getBytes())
        .build());
    ```
  </Tab>

  <Tab value="C#">
    ```csharp title="RouteEventsQueue.cs"
    await client.SendEventAsync(new EventMessage
    {
        Channel = "events:order-notify;queues:order-process",
        Metadata = "order.created",
        Body = Encoding.UTF8.GetBytes("{\"orderId\":\"ORD-200\",\"amount\":129.00}"),
    });
    ```
  </Tab>

  <Tab value="Kotlin">
    ```kotlin title="RouteEventsQueue.kt"
    client.sendEvent(EventMessage(
        channel = "events:order-notify;queues:order-process",
        metadata = "order.created",
        body = """{"orderId":"ORD-200","amount":129.00}""".toByteArray(),
    ))
    ```
  </Tab>

  <Tab value="C++">
    ```cpp title="route_events_queue.cpp"
    kubemq::EventMessage event;
    event.channel = "events:order-notify;queues:order-process";
    event.metadata = "order.created";
    event.body = R"({"orderId":"ORD-200","amount":129.00})";
    client.sendEvent(event);
    ```
  </Tab>

  <Tab value="Rust">
    ```rust title="route_events_queue.rs"
    let event = EventBuilder::new()
        .channel("events:order-notify;queues:order-process")
        .metadata("order.created")
        .body(br#"{"orderId":"ORD-200","amount":129.00}"#.to_vec())
        .build();
    client.send_event(event).await?;
    ```
  </Tab>

  <Tab value="Ruby">
    ```ruby title="route_events_queue.rb"
    msg = KubeMQ::PubSub::EventMessage.new(
      channel: 'events:order-notify;queues:order-process',
      metadata: 'order.created',
      body: '{"orderId":"ORD-200","amount":129.00}'
    )
    client.send_event(msg)
    ```
  </Tab>

  <Tab value="Elixir">
    ```elixir title="route_events_queue.exs"
    event = KubeMQ.Event.new(
      channel: "events:order-notify;queues:order-process",
      metadata: "order.created",
      body: ~s({"orderId":"ORD-200","amount":129.00})
    )
    :ok = KubeMQ.Client.send_event(client, event)
    ```
  </Tab>
</Tabs>

### All Three Patterns [#all-three-patterns]

Route a single publish to an event channel, persistent store, and a work queue simultaneously.

<Tabs groupId="language" items="['Go', 'Python', 'Node.js', 'Java', 'C#', 'Kotlin', 'C++', 'Rust', 'Ruby', 'Elixir']">
  <Tab value="Go">
    ```go title="route_all.go"
    err = client.SendEvent(ctx, kubemq.NewEvent().
        SetChannel("events:order-live;events_store:order-archive;queues:order-fulfill").
        SetMetadata("order.created").
        SetBody([]byte(`{"orderId":"ORD-300","amount":349.99}`)),
    )
    ```
  </Tab>

  <Tab value="Python">
    ```python title="route_all.py"
    client.send_event(
        EventMessage(
            channel="events:order-live;events_store:order-archive;queues:order-fulfill",
            metadata="order.created",
            body=b'{"orderId":"ORD-300","amount":349.99}',
        )
    )
    ```
  </Tab>

  <Tab value="Node.js">
    ```javascript title="route_all.js"
    await client.sendEvent({
      channel: "events:order-live;events_store:order-archive;queues:order-fulfill",
      metadata: "order.created",
      body: Buffer.from('{"orderId":"ORD-300","amount":349.99}'),
    });
    ```
  </Tab>

  <Tab value="Java">
    ```java title="RouteAll.java"
    client.sendEventsMessage(EventMessage.builder()
        .channel("events:order-live;events_store:order-archive;queues:order-fulfill")
        .metadata("order.created")
        .body("{\"orderId\":\"ORD-300\",\"amount\":349.99}".getBytes())
        .build());
    ```
  </Tab>

  <Tab value="C#">
    ```csharp title="RouteAll.cs"
    await client.SendEventAsync(new EventMessage
    {
        Channel = "events:order-live;events_store:order-archive;queues:order-fulfill",
        Metadata = "order.created",
        Body = Encoding.UTF8.GetBytes("{\"orderId\":\"ORD-300\",\"amount\":349.99}"),
    });
    ```
  </Tab>

  <Tab value="Kotlin">
    ```kotlin title="RouteAll.kt"
    client.sendEvent(EventMessage(
        channel = "events:order-live;events_store:order-archive;queues:order-fulfill",
        metadata = "order.created",
        body = """{"orderId":"ORD-300","amount":349.99}""".toByteArray(),
    ))
    ```
  </Tab>

  <Tab value="C++">
    ```cpp title="route_all.cpp"
    kubemq::EventMessage event;
    event.channel = "events:order-live;events_store:order-archive;queues:order-fulfill";
    event.metadata = "order.created";
    event.body = R"({"orderId":"ORD-300","amount":349.99})";
    client.sendEvent(event);
    ```
  </Tab>

  <Tab value="Rust">
    ```rust title="route_all.rs"
    let event = EventBuilder::new()
        .channel("events:order-live;events_store:order-archive;queues:order-fulfill")
        .metadata("order.created")
        .body(br#"{"orderId":"ORD-300","amount":349.99}"#.to_vec())
        .build();
    client.send_event(event).await?;
    ```
  </Tab>

  <Tab value="Ruby">
    ```ruby title="route_all.rb"
    msg = KubeMQ::PubSub::EventMessage.new(
      channel: 'events:order-live;events_store:order-archive;queues:order-fulfill',
      metadata: 'order.created',
      body: '{"orderId":"ORD-300","amount":349.99}'
    )
    client.send_event(msg)
    ```
  </Tab>

  <Tab value="Elixir">
    ```elixir title="route_all.exs"
    event = KubeMQ.Event.new(
      channel: "events:order-live;events_store:order-archive;queues:order-fulfill",
      metadata: "order.created",
      body: ~s({"orderId":"ORD-300","amount":349.99})
    )
    :ok = KubeMQ.Client.send_event(client, event)
    ```
  </Tab>
</Tabs>

## How Routing Works Internally [#how-routing-works-internally]

When the server receives a channel string containing `;` or `:` delimiters, it splits the targets and fans the message out to each pattern and channel independently.

<Mermaid
  chart="`graph LR
  CLIENT[&#x22;Publisher&#x22;]
  KUBEMQBROKER[&#x22;KubeMQ Server&#x22;]
  ROUTER[&#x22;Router<br/>(IsRoutable)&#x22;]
  A{{&#x22;Events channel<br/>a&#x22;}}
  B{{&#x22;Queue channel<br/>b&#x22;}}

  CLIENT -- &#x22;events:a;queues:b&#x22; --> KUBEMQBROKER
  KUBEMQBROKER -- split --> ROUTER
  ROUTER -- events --> A
  ROUTER -- queues --> B

  class CLIENT client
  class KUBEMQBROKER,ROUTER broker
  class A events
  class B queue
`"
/>

Each target is processed independently — a failure on one target does not affect the others. The server returns an error only if the routing syntax itself is invalid.

## Key Points [#key-points]

* **Atomic fan-out** — a single SDK call routes to all targets without client-side loops
* **Mixed patterns** — combine events, events\_store, and queues in any combination
* **Independent delivery** — each target processes the message according to its own pattern semantics
* **Subscriber transparency** — subscribers see messages as if published directly to their channel
