Cheat SheetsRabbitMQExchanges

Exchanges — Cheat Sheet

RabbitMQ · 5 topics. Download the PDF or the Instagram carousel and share it.

Cheat Sheet · AiCanCode.org
Exchanges
RabbitMQ5 topicsQuick revision reference
1

Direct Exchange

Routes messages to queues whose binding key exactly matches the message's routing key; ideal for simple unicast routing such as task dispatch.

  • Direct exchange routes messages where routing key = binding key (exact match).
  • The default exchange is a pre-declared direct exchange — routing key must equal the queue name.
  • One exchange can route to multiple queues with different binding keys.
  • Multiple consumers on the same queue receive messages in round-robin (competing consumers).
  • Set prefetch (QoS) to limit unacked messages per consumer — prevents starvation of slow workers.
  • Direct exchange is ideal for simple task dispatch, worker pools, and point-to-point routing.
Java — direct exchange with multiple bindings
@Configuration
public class DirectExchangeConfig {

    @Bean
    public DirectExchange notificationExchange() {
        return new DirectExchange("notifications");
    }

    // Email queue — bound with routing key "email"
    @Bean public Queue emailQueue() {
        return QueueBuilder.durable("notifications.email").build();
    }
    @Bean public Binding emailBinding(Queue emailQueue, DirectExchange exchange) {
        return BindingBuilder.bind(emailQueue).to(exchange).with("email");
    }

    // SMS queue — bound with routing key "sms"
    @Bean public Queue smsQueue() {
        return QueueBuilder.durable("notifications.sms").build();
    }
    @Bean public Binding smsBinding(Queue smsQueue, DirectExchange exchange) {
        return BindingBuilder.bind(smsQueue).to(exchange).with("sms");
    }
}

// Producer — route to email or sms based on notification type
public void sendNotification(Notification n) {
    rabbitTemplate.convertAndSend("notifications", n.getType().name().toLowerCase(), n);
    // type=EMAIL → routing key "email" → notifications.email queue
    // type=SMS   → routing key "sms"   → notifications.sms queue
}
2

Fanout Exchange

Broadcasts every message to all bound queues regardless of routing key; perfect for publish-subscribe where all consumers need every event (e.g., cache invalidation).

  • Fanout exchange broadcasts every message to all bound queues — the routing key is completely ignored.
  • Each subscriber creates its own queue and binds to the fanout exchange; the publisher does not need to know how many subscribers exist.
  • Classic use cases: cache invalidation, broadcast notifications, audit logging, event fan-out to multiple pipelines.
  • For non-persistent events (cache invalidation), use non-durable fanout exchange + exclusive auto-delete queues per consumer instance.
  • Fanout is the most efficient exchange type (no routing key matching); use it over topic when all subscribers need all messages.
  • In Spring AMQP, BindingBuilder.bind(queue).to(fanoutExchange) — no .with() key needed.
Java — Fanout Exchange Setup
Channel channel = connection.createChannel();

// Declare a durable fanout exchange
channel.exchangeDeclare("order-events", BuiltinExchangeType.FANOUT, true);

// Each subscriber declares its own queue and binds to the fanout exchange
// Routing key is ignored — pass "" by convention
channel.queueDeclare("order-events.notifications",  true, false, false, null);
channel.queueDeclare("order-events.analytics",      true, false, false, null);
channel.queueDeclare("order-events.audit-log",      true, false, false, null);

channel.queueBind("order-events.notifications", "order-events", "");  // routing key ignored
channel.queueBind("order-events.analytics",     "order-events", "");
channel.queueBind("order-events.audit-log",     "order-events", "");

// Publisher — routing key irrelevant, all bound queues receive every message
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
    .deliveryMode(2).build();  // persistent

channel.basicPublish(
    "order-events",   // exchange
    "",               // routing key — ignored by fanout
    props,
    serialize(orderEvent)
);
// → delivered to notifications, analytics, AND audit-log queues simultaneously
3

Topic Exchange

Routes by pattern-matching the routing key using * (one word) and # (zero or more words); enables flexible multi-level routing such as logs.error.# or payments.*.

  • `*` matches exactly one word; `#` matches zero or more words in a dot-delimited routing key.
  • A single routing key can match multiple queue bindings simultaneously — messages are delivered to all matching queues.
  • Binding pattern `#` alone turns a topic exchange into a fanout — use sparingly.
  • Topic exchanges combine the flexibility of routing keys with pattern-based subscription — one exchange can serve many consumer use cases.
  • In Spring AMQP, use BindingBuilder.bind(queue).to(topicExchange).with("pattern") for each binding.
  • Design routing key namespaces upfront: domain.entity.event (e.g., order.payment.failed) scales well to new event types.
RabbitMQ — Topic Routing Key Patterns
# Routing key structure:  <domain>.<entity>.<event>
# Examples:
#   order.payment.succeeded
#   order.payment.failed
#   order.shipment.dispatched
#   notification.email.sent
#   audit.*.created

# Binding patterns and what they match:
# order.#              → all order events (payment, shipment, etc.)
# order.payment.*      → order.payment.succeeded, order.payment.failed
# *.payment.*          → anything with "payment" in the middle
# #.failed             → any event ending in "failed" from any domain
# #                    → every message (fanout behaviour)
4

Headers Exchange

Routes based on AMQP message header attributes instead of routing keys; supports x-match=all (AND) or x-match=any (OR) semantics for complex attribute-based routing.

  • Headers exchanges route based on message header key-value pairs, not the routing key.
  • x-match=all (AND): all specified headers must match; x-match=any (OR): at least one must match.
  • The routing key is ignored by headers exchanges — pass an empty string.
  • Set headers via MessageProperties.setHeader() on the producer side.
  • Headers exchanges are slower than direct/topic exchanges due to header evaluation overhead.
  • Use headers exchanges for multi-dimensional routing; prefer topic exchanges for most use cases.
Java — headers exchange with whereAll/whereAny
@Configuration
public class HeadersExchangeConfig {

    @Bean
    public HeadersExchange notificationExchange() {
        return new HeadersExchange("notifications.headers");
    }

    // Queue 1: receives messages with format=pdf AND priority=high
    @Bean public Queue pdfHighQueue() {
        return QueueBuilder.durable("notifications.pdf.high").build();
    }
    @Bean public Binding pdfHighBinding(Queue pdfHighQueue,
                                         HeadersExchange exchange) {
        return BindingBuilder.bind(pdfHighQueue).to(exchange)
            .whereAll("format", "priority")          // AND semantics
            .matches(Map.of("format", "pdf", "priority", "high"));
    }

    // Queue 2: receives messages with format=email OR format=sms (any)
    @Bean public Queue emailOrSmsQueue() {
        return QueueBuilder.durable("notifications.email-or-sms").build();
    }
    @Bean public Binding emailOrSmsBinding(Queue emailOrSmsQueue,
                                            HeadersExchange exchange) {
        return BindingBuilder.bind(emailOrSmsQueue).to(exchange)
            .whereAny("format")                      // OR semantics
            .matches(Map.of("format", "email"));     // OR format=sms (separate binding)
    }
}
5

Default Exchange

Every queue is automatically bound to the default (nameless) exchange with a routing key equal to its name; publishing directly to a queue name uses this exchange implicitly.

  • Default exchange is nameless ("") and pre-exists in every vhost — you cannot delete it
  • Every queue is auto-bound to the default exchange; routing key = queue name
  • convertAndSend(queueName, message) on RabbitTemplate uses the default exchange implicitly
  • Default exchange only supports exact-name routing — no wildcards, no fanout
  • For production, prefer named exchanges for clarity, flexibility, and testability
  • Default exchange bindings cannot be removed or modified — they are broker-managed
Java — publishing via default exchange
// Java AMQP client — explicit default exchange usage
channel.basicPublish(
    "",            // empty string = default exchange
    "order.queue", // routing key = queue name
    null,
    message.getBytes()
);

// Spring RabbitTemplate shorthand (same behaviour)
@Autowired RabbitTemplate rabbitTemplate;

rabbitTemplate.convertAndSend("order.queue", orderEvent);
// Equivalent to: exchange="", routingKey="order.queue"
Learn this free with Aria, your AI tutor → AiCanCode.org/learn/rabbitmq