When one system has to tell another something, the obvious solution —call it directly and wait for the reply— is the most fragile one. If the other side is down, slow or overloaded, your system goes down with it. Asynchronous messaging breaks that coupling with an intermediary that receives and delivers. And that's where two families that get confused all the time show up: queues and streams. They look alike from the outside; inside, they answer different questions.
The problem: talking without coupling
In any architecture, systems need to exchange information without blocking or depending on the other being available at that exact instant. If service A has to wait for service B to answer, A's availability is tied to B's.
Asynchronous messaging puts an intermediary in the middle: the producer hands off its message and moves on, without waiting for the consumer to process it. The intermediary receives, stores and delivers. That way the two systems are decoupled in time.
There are two families of intermediary: queues and logs / streams. Choosing well between them is the architecture decision this article takes apart.
The queue (message queue)
A queue is exactly what it sounds like: a line. A producer puts messages in one end; a consumer pulls them out the other.
- The producer drops a message into the queue and carries on with its work. It doesn't wait for a reply.
- The message stays stored in the queue until someone takes it. If the consumer is down, the message waits.
- A consumer pulls messages out of the queue, one by one, and processes them.
- Once consumed and acknowledged, the message is removed from the queue: it did its job and it's gone.
That model is good for three things: distributing work (several consumers take turns on messages from the same queue, scaling processing), guaranteeing delivery (the message isn't lost: it waits until processed and acknowledged) and decoupling producer from consumer. Classic examples: IBM MQ and RabbitMQ.
The stream (distributed log)
A stream works on a different logic. Instead of a line you pull from and delete, it's a record that only grows. The reference case is Apache Kafka.
- Events are appended to the end of a partitioned, replicated log. They aren't inserted in the middle or pulled out: they're only added.
- Events are retained for a configured time and not deleted on read. Reading doesn't consume.
- Multiple consumers read independently, each at its own pace, tracking where they are with their offset (their position in the log).
- Because the events are still there, a consumer can re-read from the past: the stream is replayable.
That design is built for high volume and for many different systems to consume the same stream without stepping on each other. Nobody "drains" the stream: it's a durable source of truth of what happened, and each reader walks it at its own pace.
The difference that matters
Boiled down to the essentials, the distinction is a single one and it changes everything:
- Queue = "consume and it's gone". Work is distributed once among consumers; each message is processed by one, and once processed it disappears.
- Stream = "durable, replayable history". The same event can be read by many readers, each independent, and it can be re-read from the past.
Thinking the difference is speed vs slowness. It isn't. It's not that one is fast and the other slow: they're different models of messaging. One distributes and deletes; the other retains and replays. Choosing by "which is faster" is choosing the wrong question.
MQ and Kafka, side by side
| Feature | MQ (queue) | Kafka (stream) |
|---|---|---|
| Model | Queue | Distributed log |
| Is the message deleted on read? | Yes | No, it's retained |
| How many consume the same message? | One | Many, independent |
| Replayable? | No | Yes |
| Strength | Guaranteed transactional delivery | High-volume streaming |
| Examples | IBM MQ, RabbitMQ | Apache Kafka |
Common mistakes
"Kafka replaces MQ." No. They solve different needs. Kafka is not a traditional queue (it retains events and replays them), and a queue is not an event log (it delivers once and deletes). Picking the wrong one doesn't fail immediately: you pay for it later, in complexity.
- Believing "everything needs Kafka". Kafka is powerful, but it adds operations: partitions, offsets, retention, cluster. To distribute work with guaranteed delivery, a queue is simpler and more appropriate.
- Confusing a message with an event. A queue message is an instruction for someone to do something (and then it disappears). A stream event is a fact that happened and stays recorded for whoever wants to read it. They aren't interchangeable.
- Forcing the wrong model onto the problem. Using a queue where you need to re-read history, or a stream where you need exclusive delivery with acknowledgment, leaves you fighting the tool.
The banking angle
In banking this distinction isn't theoretical: it defines which technology owns each flow.
IBM MQ is the de facto standard for core transactional messaging. A payment instruction cannot be lost or duplicated: it has to arrive, exactly once, and be acknowledged. A queue's guaranteed delivery —the message waits until it's processed and only then disappears— is exactly that property. That's why the payment engine, account-to-account transfers and messaging between critical systems run on queues.
Kafka fits the other side: event streams, real-time analytics and fraud-detection pipelines. There you want many systems —scoring, monitoring, dashboards, rules— to read the same event stream independently, at their own pace, and to reprocess the history when a model changes. That's exactly what a distributed log does well.
It's not MQ or Kafka. Both live in the same bank, each where it shines. The question isn't which one wins; it's what problem you have: distributing work with guaranteed delivery, or broadcasting a replayable event history to many readers. Knowing that, the choice stops being a trend and goes back to being engineering.