Rabbit Relay

Exchanges, Queues, and Bindings

How RabbitMQ routes messages through exchanges, bindings, and queues

RabbitMQ routing is based on three core resources:

exchange -> binding -> queue

A producer publishes to an exchange.

RabbitMQ uses bindings to decide which queues should receive the message.

A consumer reads from a queue.


Mental model

producer
  -> exchange
    -> binding
      -> queue
        -> consumer

Rabbit Relay keeps this model explicit:

const sub = await broker
  .queue("orders.q")
  .exchange("orders.ex", {
    exchangeType: "topic",
    routingKey: "orders.*",
  });

This means:

CodeRabbitMQ concept
"orders.ex"exchange
"orders.q"queue
"orders.*"binding routing key
exchangeType: "topic"exchange type

Exchange

An exchange receives published messages.

The producer does not publish directly to a queue.

It publishes to an exchange.

.exchange("orders.ex", {
  exchangeType: "topic",
});

Common exchange types:

Exchange typeMeaning
topicroute by pattern matching
directroute by exact key
fanoutbroadcast to all bound queues
headersroute using headers

Most Rabbit Relay examples use topic.


Queue

A queue stores messages until a consumer receives them.

.queue("orders.q")

A queue can have one or more consumers.

If no consumer is running, messages can wait in the queue.


Binding

A binding connects an exchange to a queue.

The binding can include a routing key.

.exchange("orders.ex", {
  routingKey: "orders.*",
});

This tells RabbitMQ:

send messages from orders.ex to orders.q
when the routing key matches orders.*

Routing key

The routing key is the label RabbitMQ uses to route a message.

By default, Rabbit Relay uses the event name as the publish routing key.

const orderCreated = event("orders.created", "v1").of<OrderCreated>();

await pub.produce(orderCreated(data));

Default routing key:

orders.created

If the queue binding is:

orders.*

then orders.created matches and the message goes to the queue.


Topic exchange matching

Topic exchanges support patterns.

PatternMatches
orders.createdonly orders.created
orders.*orders.created, orders.paid
orders.#orders.created, orders.payment.failed, etc.
#everything

Use specific patterns when possible.

Use # only when you intentionally want broad consumption.


Fanout exchange

Fanout exchanges ignore routing keys.

Every bound queue receives the message.

await broker
  .queue("audit.q")
  .exchange("events.broadcast", {
    exchangeType: "fanout",
  });

This is useful for broadcast-style events.


Direct exchange

Direct exchanges use exact routing-key matching.

await broker
  .queue("payments.q")
  .exchange("commands.ex", {
    exchangeType: "direct",
    routingKey: "payments.authorize",
  });

This is useful for command-like routing.


Common mistake: publishing to a queue

In RabbitMQ, producers publish to exchanges, not queues.

For publisher-only code, use broker.exchange() to declare just the exchange — no queue, no binding, no consumer. This keeps topology ownership clean in multi-process setups: the producer owns the exchange; the consumer owns the queue and bindings.

const pub = await broker.exchange("orders.ex", {
  exchangeType: "topic",
});

await pub.produce(orderCreated(data));

The important part for publishing is the exchange. A publisher interface has an empty queue and binding plan:

pub.planTopology();
// { exchanges: [...], queues: [], bindings: [] }

Only use .queue(...).exchange(...) when the same process also consumes from the queue via consume().


Common mistake: wrong routing key

If a message is published but no consumer receives it, check:

  • the event name
  • the publish routing key
  • the binding routing key
  • the exchange type

Example:

event("orders.created", "v1")

with binding:

routingKey: "payments.*"

does not match.


Summary

  • Producers publish to exchanges
  • Queues store messages for consumers
  • Bindings connect exchanges to queues
  • Routing keys decide where messages go
  • Rabbit Relay maps .queue(...).exchange(...) directly to RabbitMQ topology
  • Use broker.exchange(...) for exchange-only (publisher-only) topology

On this page