1. Omid Sayfun
  2. /
  3. Notebook
  • Home
  • About
  • Notebook
  • Token Usage
  • Whisper Usage
Tools
  • Agent Knowledge Base

RabbitMQ exchange vs queue, explained

August 14, 2024 · Updated on August 09, 2026

A common assumption is that you publish messages straight into a RabbitMQ queue. You don't. Every message goes to an exchange first. The exchange routes it, and one or more queues store it. That is the difference between an exchange and a queue: routing versus storage. Once you see that separation, the rest of RabbitMQ makes sense.

I write short, practical notes like this one. Get the next one by email:

Unsubscribe anytime.

Exchanges route messages, they don't store them

A producer publishes a message to an exchange, along with a routing key. The exchange holds no messages. It looks at the routing key and its bindings, then forwards the message to the matching queues.

RabbitMQ has four exchange types, and they differ only in how they match:

  1. Direct Exchange: Routes to queues whose binding key exactly equals the message's routing key. One key, one match.
  2. Fanout Exchange: Ignores the routing key. It copies the message to every queue bound to it. Use it for broadcasts.
  3. Topic Exchange: Matches routing keys against patterns. A * matches one word, a # matches zero or more. A binding key of orders.*.created catches orders.eu.created and orders.us.created.
  4. Headers Exchange: Ignores the routing key entirely and matches on message headers instead. Useful when routing depends on more than one attribute.

Choosing between the exchange types comes down to two questions. Direct vs topic: do you need wildcards in your routing? Topic vs fanout: do consumers need to filter messages, or does everyone get everything?

There is also a default exchange with no name. When a client appears to publish "directly to a queue", it is actually publishing to the default exchange, which routes by queue name. So even the simplest setup goes through an exchange.

Queues store messages until a consumer takes them

A queue is where messages wait. It delivers them in first-in, first-out order to whichever consumer is subscribed.

Three queue features matter in practice:

  • Durability: A durable queue survives a broker restart. Messages marked persistent are written to disk and are still there after a crash.
  • Message Acknowledgment: The consumer confirms each message after processing it. If the consumer dies before the ack, RabbitMQ redelivers the message to another consumer.
  • Priorities: A priority queue delivers higher-priority messages before lower-priority ones, regardless of arrival order.

Queues also come in types: classic, quorum, and stream. Quorum queues replicate messages across nodes, so they survive the loss of a broker, not just a restart. For most single-node setups, classic queues are fine.

Bindings connect the two

The full path is short. The producer publishes a message to an exchange. The exchange checks its bindings and routes the message to zero or more queues. The message sits in each queue until a consumer picks it up and acknowledges it.

Bindings are the part you configure: a binding links a queue to an exchange, optionally with a binding key. Two terms sound alike here and trip people up. The routing key is set by the producer on each message. The binding key is set on the binding when you connect a queue to an exchange. The exchange compares one against the other. Routing behavior is not a property of the queue or the exchange alone; it comes from the bindings between them. For a real TypeScript implementation that puts this together, I built an RPC pattern with RabbitMQ that shows how producers, exchanges, and queues work end to end in a service-to-service scenario.

tl;dr

In RabbitMQ, exchanges are message routers that don't store messages, while queues are message storage units. Exchanges decide where messages go based on routing rules, and queues hold messages until they're processed by consumers. This separation allows for flexible and efficient message handling in distributed systems. If you're designing a larger architecture, this pattern fits naturally with CQRS and Event Sourcing, where the exchange/queue layer handles event routing between the command and query sides.

Join My Newsletter

Occasional notes on software, tools, and things I learn. No spam.

Unsubscribe anytime.

Continue Reading

  • Embeddings rot too. Running pgvector in production.Aug 28, 2026
  • Stop shipping retrieval changes on vibesAug 25, 2026
  • Your RAG is confidently wrong without hybrid searchAug 21, 2026
  • Stop tuning everything. pgvector has three knobs that matter.Aug 18, 2026
  • Your agent's knowledge base is lying to you. Run these 14 checks.Aug 18, 2026