Home/Learn/RabbitMQ/Fanout Exchange

Fanout Exchange

Beginner
Exchanges

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).

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.

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

Spring 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.

Java — Spring AMQP FanoutExchange
@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).

Java — Fanout vs Topic Use Cases
// 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 Aria
1

What is a fanout exchange and when would you use it over a direct exchange?

EasyAmazon
2

How does a fanout exchange implement the publish-subscribe pattern?

EasyFlipkart
3

What happens to the routing key in a fanout exchange?

EasyInfosys
4

How would you implement cache invalidation across 20 service instances using RabbitMQ?

MediumUber
5

When would you choose a topic exchange over a fanout exchange for pub-sub?

MediumNetflix

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.

Loading discussion…