100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Messaging

Topic Exchange Explained

Learn how RabbitMQ's topic exchange uses wildcard pattern matching on dot-separated routing keys for flexible, hierarchical message routing.

Exchanges & RoutingIntermediate10 min readJul 10, 2026
Analogies

What Is a Topic Exchange?

A topic exchange routes messages by matching a dot-separated routing key against binding patterns that may contain two wildcard characters: '*' (star), which matches exactly one word, and '#' (hash), which matches zero or more words. A routing key such as 'order.us-east.shipped' can be matched by binding patterns like 'order.*.shipped', 'order.#', or 'order.us-east.*', giving you hierarchical, pattern-based routing that sits between the rigid exact-match of a direct exchange and the unconditional broadcast of a fanout exchange. This makes topic exchanges the most flexible and commonly used exchange type for real-world event-driven systems where routing needs vary by consumer.

🏏

Cricket analogy: It's like a cricket commentary feed structured as 'match.innings.event' where a subscription to 'match.*.wicket' catches wickets from any innings, while 'match.2.#' catches every event from the second innings alone.

Wildcard Semantics: * and #

The star wildcard substitutes for exactly one word between dots — 'order.*.shipped' matches 'order.us-east.shipped' but not 'order.us-east.warehouse.shipped' because the star cannot span two words, and it also won't match 'order.shipped' because it requires exactly one word to be present in that position. The hash wildcard is more permissive, matching zero or more words including none at all — 'order.#' matches 'order', 'order.shipped', and 'order.us-east.warehouse.shipped' equally, which is why '#' alone as a binding key behaves identically to a fanout exchange, matching every possible routing key on that exchange.

🏏

Cricket analogy: The star is like a scorecard filter for 'session.*.wicket' matching exactly one named session (morning, afternoon) before wicket, while the hash in 'session.#' matches any number of qualifiers, including a bare 'session' entry with no detail at all.

Declaring Bindings with Wildcards

python
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

channel.exchange_declare(exchange='orders_topic', exchange_type='topic', durable=True)

result = channel.queue_declare(queue='shipping_alerts', durable=True)

# Catch every 'shipped' event regardless of region
channel.queue_bind(exchange='orders_topic', queue='shipping_alerts', routing_key='order.*.shipped')

# Catch everything happening to us-east orders, any depth
channel.queue_bind(exchange='orders_topic', queue='shipping_alerts', routing_key='order.us-east.#')

channel.basic_publish(
    exchange='orders_topic',
    routing_key='order.us-east.shipped',
    body='Order 88213 shipped from us-east warehouse',
)

connection.close()

Performance and Design Considerations

Topic exchange matching is more computationally expensive than direct exchange matching because RabbitMQ must evaluate each binding pattern's wildcard segments against the routing key rather than doing a simple hash-table lookup, though in practice this overhead is negligible for the vast majority of workloads and RabbitMQ optimizes pattern matching internally with a trie-like structure. The bigger design consideration is routing key schema discipline: because topic routing depends entirely on a consistent dot-separated naming convention, teams should document and enforce a routing key schema (e.g., '{entity}.{region}.{event}') early, since retrofitting a new segment into existing keys later breaks every existing binding pattern that assumed a fixed word count.

🏏

Cricket analogy: It's like a scoring app that must parse ball-by-ball commentary strings instead of just checking a fixed 'out/not out' flag — more parsing work per delivery, but negligible compared to the cost of getting the innings numbering scheme wrong mid-season.

A binding key of just '#' on a topic exchange matches every routing key, including keys with zero dots, making it functionally equivalent to a fanout exchange for that binding. This is a handy debugging trick: bind a temporary queue with '#' to a topic exchange to observe every message flowing through it in production without disrupting existing consumers.

  • Topic exchanges route using dot-separated routing keys matched against wildcard binding patterns.
  • The '*' wildcard matches exactly one word; '#' matches zero or more words.
  • A binding of '#' alone matches every routing key, behaving like a fanout exchange.
  • Topic exchanges sit between direct (exact match) and fanout (unconditional) in flexibility.
  • Pattern matching has more overhead than direct exchange lookups, though RabbitMQ optimizes it internally.
  • A consistent, documented routing key schema is essential since retrofitting new segments breaks existing bindings.
  • Topic exchanges are the most commonly used exchange type in real-world event-driven RabbitMQ systems.

Practice what you learned

Was this page helpful?

Topics covered

#Messaging#RabbitMQStudyNotes#Database#TopicExchangeExplained#Topic#Exchange#Explained#Wildcard#StudyNotes#SkillVeris