System Design
Pub-Sub vs Message Queue vs Message Broker
Three messaging terms that get tangled together constantly. They're related but distinct - one is a delivery pattern, one is a different delivery pattern, and one is the system that runs them. Here's how they actually fit.
These three terms - publish-subscribe, message queue, and message broker - show up together constantly in discussions of distributed systems, and they're constantly conflated. They're related, but they are not the same thing, and confusing them leads to muddled designs and muddled interviews. The clearest way to untangle them: two of these are delivery patterns (different ways messages get from senders to receivers), and one is the system that implements those patterns. Once you see that, the confusion dissolves.
This guide pins down all three: what a message queue is, what publish-subscribe is, how they differ, and where a message broker fits as the thing that runs them.
Message Queue: one message, one consumer
A message queue delivers each message to exactly one consumer. Producers put messages into the queue, and consumers pull messages out - but each message is taken by a single consumer and then it's gone. If multiple consumers are reading from the same queue, they share the work: each message goes to one of them, so the load is distributed, but no message is processed twice.
The defining property is competing consumers. Multiple consumers compete to pull from the queue, and the queue hands each message to just one. This is exactly what you want for distributing work - five consumers on a queue process roughly five times as fast, because they split the messages among themselves.
graph LR
P[Producer] --> Q[(Queue)]
Q -->|message 1| C1[Consumer A]
Q -->|message 2| C2[Consumer B]
Q -->|message 3| C3[Consumer C]
This diagram shows a message queue with competing consumers. A producer puts messages into the queue. Three consumers pull from it, but each message goes to only one consumer - message 1 to consumer A, message 2 to consumer B, message 3 to consumer C. The work is distributed, and no message is processed more than once.
Use a queue when you have work to distribute and each task should be done exactly once: processing orders, handling uploads, sending individual emails. Adding consumers scales the throughput.
Publish-Subscribe: one message, many subscribers
Publish-subscribe (pub-sub) works differently. Instead of each message going to one consumer, every message is delivered to all interested subscribers. Producers (called publishers) send messages to a topic, and every consumer (called a subscriber) that has subscribed to that topic receives its own copy of every message.
The defining property is broadcast. A message published to a topic fans out to all subscribers - each one gets it. This is what you want when multiple parts of the system all need to react to the same event independently.
graph LR
P[Publisher] --> T[Topic: 'order placed']
T -->|copy| S1[Subscriber: Inventory]
T -->|copy| S2[Subscriber: Email]
T -->|copy| S3[Subscriber: Analytics]
This diagram shows publish-subscribe. A publisher sends a message to a topic called "order placed." Every subscriber to that topic receives its own copy - the inventory service, the email service, and the analytics service each get the message and react independently. Unlike a queue, the message goes to all subscribers, not just one.
Use pub-sub when multiple independent consumers all need the same event. When an order is placed, the inventory system needs to know, the email system needs to know, and analytics needs to know - and they're independent. Publish "order placed" once, and all three receive it. The publisher doesn't even know who's listening; subscribers can be added or removed without changing the publisher at all.
Important: The core distinction: a message queue delivers each message to one consumer (work distribution); publish-subscribe delivers each message to all subscribers (event broadcast). Queue = "do this task, someone." Pub-sub = "this happened, everyone who cares should know." Picking the wrong one is a real design error: use a queue when you meant to broadcast and only one consumer reacts; use pub-sub when you meant to distribute work and everyone does it redundantly.
The key comparison
| Message Queue | Publish-Subscribe | |
|---|---|---|
| Each message goes to | One consumer | All subscribers |
| Purpose | Distribute work | Broadcast events |
| Multiple consumers | Share the load | Each gets every message |
| Producer knows consumers? | No | No |
| Analogy | A task list workers pull from | A newsletter sent to all subscribers |
| Use when | A task should be done once | Many parts must react to one event |
Message Broker: the system that runs both
So where does a message broker fit? A message broker is the software system that implements messaging - it's the infrastructure that actually receives messages from producers, stores them, and delivers them to consumers, supporting queue patterns, pub-sub patterns, or both.
In other words: queue and pub-sub are patterns (ways messages flow); a broker is the thing that provides those patterns. When you use a message queue or a pub-sub topic, there's usually a message broker underneath making it work - managing the storage, the routing, the delivery, the acknowledgments, the retries. The broker is the engine; the queue and pub-sub are two modes that engine can run in.
A broker typically handles the hard parts of messaging so you don't have to: durably storing messages so they survive crashes, routing them to the right consumers, tracking acknowledgments and retrying failed deliveries, and managing the topics and queues themselves. Real systems like RabbitMQ, Apache Kafka, and cloud messaging services are message brokers - and most of them support both queue-style and pub-sub-style delivery, because real applications need both.
Tip: Emeka's note from production: In the pipeline I run, we use both patterns through the same underlying broker, for different jobs. Raw viewing events fan out pub-sub style, because many independent consumers need them - the real-time personalization system, the operational dashboards, and the batch aggregation jobs all subscribe to the same event stream and each gets its own copy. But within a specific processing job, we use queue semantics so a pool of workers can split the load, each handling different events exactly once. Same broker, two patterns, chosen per use case. The mistake I see people make is treating "message broker" as a synonym for one pattern - it's the system, and which pattern you use is a separate decision you make per data flow.
A worked example: an order is placed
Let me make the distinction concrete with a single event flowing through both patterns. A customer places an order. Several things must happen, and they fall into two categories.
Broadcast (pub-sub): Lots of independent parts of the system care that an order was placed. Inventory needs to decrement stock. The email service needs to send a confirmation. Analytics needs to record the sale. The recommendation engine wants to learn from the purchase. None of these depend on each other - they just all need to know the order happened. So "order placed" is published to a topic, and each of these services subscribes and gets its own copy, reacting independently. Adding a fifth service later (a loyalty-points system) is trivial - it just subscribes to the same topic, and the order service doesn't change at all.
Work distribution (queue): Now consider one of those reactions - sending the confirmation email. Sending email is slow, and at high volume you want several workers handling it. So the email service puts "send confirmation for order #123" onto a queue, and a pool of email-worker consumers pulls from it, each handling different emails. Here you want each email sent once, by one worker - classic queue semantics.
So a single business event uses both patterns: pub-sub to broadcast "order placed" to all interested services, and a queue within the email service to distribute the email-sending work. This is exactly how real systems combine the two - and seeing it in one example makes the distinction click.
Can you combine them? Consumer groups
A powerful pattern blurs the line between queue and pub-sub usefully: consumer groups. Some systems (notably Kafka) let you have multiple groups of consumers on the same stream, where each message is broadcast to every group (pub-sub style), but within a group, it goes to only one consumer (queue style).
In practice: the analytics group, the personalization group, and the archival group each receive every event (pub-sub across groups) - but within the analytics group, several consumer instances split the events among themselves for parallel processing (queue within the group). This gives both behaviors at once: broadcast to independent groups, load-distribution within each. It's how high-scale systems get the benefits of both patterns from a single event stream. (This is exactly the setup I rely on in the viewing pipeline - many groups each consuming the full event stream, with load split inside each group.)
What a message broker handles for you
It's worth appreciating how much work a broker does, because it explains why you use one rather than building messaging yourself. A good broker handles durable storage (persisting messages so they survive a crash, not just living in memory), routing (getting each message to the right queue or topic and consumers), delivery tracking (knowing which messages were acknowledged and redelivering those that weren't), retries and dead-lettering (handling messages that fail to process), ordering guarantees (within the broker's limits), and scaling (high throughput, many producers and consumers). Reimplementing all of that correctly is a serious undertaking full of subtle distributed-systems pitfalls - which is why mature brokers are such valuable infrastructure. You get decades of hard-won reliability engineering by using one.
Common brokers and the patterns they favor
The well-known brokers each lean toward particular patterns and strengths:
- RabbitMQ - a flexible, traditional broker that excels at both queue and pub-sub with rich routing. Great for complex routing and reliable work distribution.
- Apache Kafka - a high-throughput, log-based system built for massive-scale event streaming, with consumer groups enabling the broadcast-plus-distribution pattern. The go-to for high-volume event streams.
- Cloud messaging services (like Google Cloud Pub/Sub) - managed services providing pub-sub and queue semantics without you operating the infrastructure.
- Redis - lightweight pub-sub and queue capabilities alongside its other features, good for simpler needs.
The choice depends on scale, the patterns you need, ordering and durability requirements, and managed versus self-hosted. But all are brokers - systems providing the patterns - which loops back to the core point: broker is the system, queue and pub-sub are the patterns it runs.
Choosing the right pattern
When designing a data flow, ask a simple question: does this message represent work to be done, or an event that happened?
- If it's work to be done - a task one worker should handle once - use a queue. "Process this payment," "send this email," "resize this image." You want exactly one consumer per task, and you scale by adding workers that share the load.
- If it's an event that happened - a fact multiple parties may care about - use pub-sub. "An order was placed," "a user signed up." You want every interested party to learn about it independently, and to add new parties without touching the publisher.
A clear sign you've chosen wrong: if you're using a queue but want multiple different systems to all react to the same message, you actually want pub-sub. And if you're using pub-sub but only ever have one consumer processing each message once, you probably wanted a queue. Many architectures deliberately use pub-sub at the "something happened" boundaries between major subsystems, and queues inside each subsystem for distributing the resulting work - that layered use of both, over a shared broker, is a hallmark of well-designed large systems.
How to keep them straight
The clean mental model:
- Message broker - the system (the infrastructure that moves messages around).
- Message queue - a pattern the broker provides, where each message goes to one consumer (distribute work).
- Publish-subscribe - another pattern the broker provides, where each message goes to all subscribers (broadcast events).
So "pub-sub vs message queue" is really a comparison of two delivery patterns, while "message broker" is the thing that implements whichever pattern you choose. They're not three competing options - they're two patterns and the engine that runs them.
Interview: When messaging comes up in a design, using these terms precisely is a clear signal of depth. Distinguish the pattern you need from the system providing it: "Many services need to react to this event, so I'll use pub-sub - publish the event to a topic and each interested service subscribes. I'll run it on a message broker that also gives me queue semantics for the work-distribution parts of the system." Showing you know that a broker provides both patterns, and choosing the right pattern per data flow, separates a real answer from buzzword-matching.
A simple way to remember it
If the three terms still feel slippery, here's the one-line version to lock in: the broker is the post office; the queue and pub-sub are two kinds of mail. A queue is like a stack of tasks where each delivery goes to exactly one worker who handles it. Pub-sub is like a newsletter the post office copies and delivers to everyone who subscribed. And the post office itself - the building, the trucks, the sorting, the guarantee that mail isn't lost - is the broker, which runs both kinds of delivery. You don't choose "post office or newsletter"; you choose what kind of mail you're sending (a one-person task or a broadcast), and the post office delivers it accordingly. Holding that picture keeps the three from collapsing into each other: one system (the broker), two delivery patterns (queue and pub-sub) it provides.
The bottom line
A message queue delivers each message to one consumer, for distributing work. Publish-subscribe delivers each message to all subscribers, for broadcasting events. A message broker is the system that implements these patterns - it's the engine, and queue and pub-sub are two modes it can run in. The relationship is simple once you see it: two patterns, one system that provides them, and most real systems use both patterns through the same broker for different purposes.
Get these distinctions right and your messaging designs become clear: pick the pattern that matches the data flow (distribute or broadcast), and run it on the broker that provides it. We cover messaging patterns and the systems behind them across System Design Fundamentals.
Go deeper
- Publish–subscribe pattern (Wikipedia) - the broadcast delivery model in depth.
- Message broker (Wikipedia) - the system that implements messaging patterns.
- Google Cloud Pub/Sub documentation - a real pub-sub system and its concepts.
- RabbitMQ - a broker supporting both queue and pub-sub patterns, with clear conceptual guides.