An exchange is the router that decides where messages go. In this episode you learn the five exchange types: direct, fanout, topic, headers, and default, along with routing keys, binding keys, exchange-to-exchange binding, alternate exchanges, and implementing the publish/subscribe pattern.

In episode 4, you published to a queue via a routing key without understanding why it worked. The secret: you were using the default exchange, which automatically sends messages to the queue whose name matches the routing key. Now it's time to open the real box — the exchange.
An exchange is RabbitMQ's router. Producers never send messages directly to a queue; they always publish to an exchange, and the exchange decides which queue the message goes to based on its type and bindings. The exchange type you choose determines the level of routing flexibility you can achieve.
This episode introduces the five exchange types, how routing keys and binding keys work, advanced features like exchange-to-exchange binding and alternate exchanges, and closes with implementing the publish/subscribe pattern using a fanout exchange — the most fundamental pattern for broadcasting messages.
A direct exchange delivers messages to queues whose binding key is exactly the same as the message's routing key. This is similar to sending a letter to a specific address. For example, a routing key of errors only reaches queues bound with the key errors.
rabbitmqadmin declare exchange name=logs_direct type=direct
rabbitmqadmin declare queue name=error_queue durable=true
rabbitmqadmin declare binding source=logs_direct destination=error_queue routing_key=errorThe rabbitmqadmin declare binding command above only forwards messages with the routing key error to error_queue.
A fanout exchange ignores the routing key entirely and sends a copy of the message to all queues bound to it. This is the basis of the publish/subscribe pattern. It's suitable for broadcasting, like real-time notifications to all users.
A topic exchange matches routing keys against the wildcard patterns * and # — we'll break these down in depth in episode 7. A headers exchange ignores the routing key and matches based on message headers, using the x-match: all or x-match: any rules.
The default exchange is a nameless direct exchange ("") that exists automatically in every vhost. All queues are bound to the default exchange with a routing key equal to the queue name. This is why channel.basic_publish(exchange="", routing_key="task_queue", ...) works without declaring an exchange.
A routing key is a message attribute set by the producer when publishing. A binding key is a binding attribute set when connecting an exchange and a queue. Both are used by the exchange to determine routing. The rules of the game:
publish(exchange, routing_key, message)
│
▼
exchange (type determines the matching)
│ matched against binding key
▼
queue → consumerrouting_key == binding_key.routing_key is pattern-matched against the binding key.RabbitMQ allows an exchange to be bound to another exchange. A message that enters exchange A can be forwarded to exchange B according to its rules. This makes it possible to build complex, hierarchical routing topologies without changing producers.
An alternate exchange is a fallback: if a message cannot be routed by the main exchange (no matching queue exists), the message is forwarded to the alternate exchange instead of being silently discarded.
rabbitmqadmin declare exchange name=unroutable type=fanout
rabbitmqadmin declare exchange name=main type=direct arguments='{"alternate-exchange":"unroutable"}'With the configuration above, messages that fail to be routed by the main exchange go to the unroutable fanout, where you can monitor rogue messages.
The publish/subscribe pattern makes a message received by all subscribers. In RabbitMQ, this pattern is implemented with a fanout exchange:
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
channel = connection.channel()
channel.exchange_declare(exchange="notifikasi", exchange_type="fanout")
channel.basic_publish(exchange="notifikasi", routing_key="", body=b"berita terbaru")
print("pesan di-broadcast")
connection.close()Notice the routing_key="" — fanout ignores the routing key. All queues bound to the notifikasi exchange will receive this message.
Every subscriber must have its own queue, usually a temporary queue that is deleted automatically when the consumer stops:
result = channel.queue_declare(queue="", exclusive=True)
queue_name = result.method.queue
channel.queue_bind(exchange="notifikasi", queue=queue_name)The channel.queue_declare(queue="", exclusive=True) command creates a unique queue with a random name, and exclusive=True ensures the queue is deleted when the connection closes. This is the pattern used to broadcast to many consumers correctly.
Tip
Always ask two questions before choosing an exchange: how many consumers must receive the same message? If all of them, use fanout. If only those matching certain criteria, use direct or topic.
In episode 6 you understood the exchange's role as a router, compared the five exchange types, mastered routing keys and binding keys, and built the publish/subscribe pattern with a fanout exchange and temporary queues.
Key takeaways:
In the next episode we will dive into advanced routing with topic exchanges — star and hash wildcards, hierarchical topic design, and headers exchanges with x-match. This will let you design multi-criteria routing systems like routing logs based on severity and module!