Fanout Exchange
BeginnerBroadcasts every message to all bound queues regardless of routing key; perfect for publish-subscribe where all consumers need every event (e.g., cache invalidation).
Overview
A fanout exchange broadcasts every message it receives to all queues that are bound to it — the routing key is completely ignored. This is the simplest exchange type and the natural choice for publish-subscribe patterns where multiple independent consumers all need a copy of every event. Classic use cases: cache invalidation (broadcast to all service instances), system-wide notifications, audit logging (every service gets a copy), and event fan-out to multiple processing pipelines. Each consumer binds its own queue to the fanout exchange; adding a new consumer is as simple as declaring a new queue and binding it — the publisher does not change.
Fanout Exchange Setup
Declare a fanout exchange, then bind as many queues as you need. The routing key in basicPublish is ignored — all bound queues receive the message. Each consumer has its own independent queue so they process messages at their own pace.
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 simultaneouslySpring AMQP — FanoutExchange Configuration
Spring AMQP makes fanout configuration clean with FanoutExchange and BindingBuilder. Each subscriber service declares its own queue; the shared exchange is typically declared in a common configuration library.
@Configuration
public class FanoutConfig {
@Bean
public FanoutExchange orderEventsFanout() {
return new FanoutExchange("order-events", true, false);
}
// Notification service — its own queue bound to the fanout
@Bean
public Queue notificationQueue() {
return QueueBuilder.durable("order-events.notifications").build();
}
@Bean
public Binding notificationBinding(Queue notificationQueue,
FanoutExchange orderEventsFanout) {
// No routing key needed — BindingBuilder.bind().to(fanout)
return BindingBuilder.bind(notificationQueue).to(orderEventsFanout);
}
// Analytics service — separate queue, same fanout
@Bean
public Queue analyticsQueue() {
return QueueBuilder.durable("order-events.analytics").build();
}
@Bean
public Binding analyticsBinding(Queue analyticsQueue, FanoutExchange orderEventsFanout) {
return BindingBuilder.bind(analyticsQueue).to(orderEventsFanout);
}
}
// Publisher — routing key not needed
@Service
@RequiredArgsConstructor
public class OrderEventPublisher {
private final RabbitTemplate rabbitTemplate;
public void publish(OrderEvent event) {
// FanoutExchange — empty routing key, exchange name only
rabbitTemplate.convertAndSend("order-events", "", event);
}
}Fanout vs Topic for Pub-Sub
Fanout is the simplest choice for pub-sub — every subscriber gets every message. Use a topic exchange instead when: - Only some subscribers need certain event types (e.g., only the billing service needs PaymentFailed events) - You want to add routing flexibility without changing publishers - You have a heterogeneous event stream from one exchange
Fanout is the right default when all subscribers truly need all events. It is the most efficient exchange type (no routing key matching overhead).
// Fanout: every subscriber gets every message
// Use when: all consumers need all events
// Examples: cache.invalidated, config.changed, user.logged-in (audit)
// Topic: selective delivery based on routing key patterns
// Use when: different subscribers need different event types
// Examples: "order.payment.failed" → only billing
// "order.#" → fulfilment gets everything order-related
// Cache invalidation — classic fanout use case
// Every service instance needs to invalidate its local cache
@Configuration
public class CacheInvalidationConfig {
@Bean
public FanoutExchange cacheInvalidation() {
return new FanoutExchange("cache-invalidation", false, true);
// Non-durable, auto-delete: cache invalidation doesn't need persistence
}
@Bean
public Queue myInstanceCacheQueue() {
// Exclusive, auto-delete: deleted when this service instance disconnects
return QueueBuilder.nonDurable()
.exclusive()
.autoDelete()
.build();
}
@Bean
public Binding cacheBinding(Queue myInstanceCacheQueue, FanoutExchange cacheInvalidation) {
return BindingBuilder.bind(myInstanceCacheQueue).to(cacheInvalidation);
}
}Key Points to Remember
- 1Fanout exchange broadcasts every message to all bound queues — the routing key is completely ignored.
- 2Each subscriber creates its own queue and binds to the fanout exchange; the publisher does not need to know how many subscribers exist.
- 3Classic use cases: cache invalidation, broadcast notifications, audit logging, event fan-out to multiple pipelines.
- 4For non-persistent events (cache invalidation), use non-durable fanout exchange + exclusive auto-delete queues per consumer instance.
- 5Fanout is the most efficient exchange type (no routing key matching); use it over topic when all subscribers need all messages.
- 6In Spring AMQP, BindingBuilder.bind(queue).to(fanoutExchange) — no .with() key needed.
Interview Questions
Sign in to ask AriaWhat is a fanout exchange and when would you use it over a direct exchange?
How does a fanout exchange implement the publish-subscribe pattern?
What happens to the routing key in a fanout exchange?
How would you implement cache invalidation across 20 service instances using RabbitMQ?
When would you choose a topic exchange over a fanout exchange for pub-sub?
Ask Aria about Fanout Exchange
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.