RabbitMQ vs Kafka vs Pulsar: The decision tree your team should actually use
Three Different Machines, Not Three Options
The persistent framing of RabbitMQ, Kafka, and Pulsar as competitors obscures the real insight: they solve fundamentally different problems with different data models. Choosing between them isn't a feature comparison — it's an architecture decision.
| Dimension | RabbitMQ | Kafka | Pulsar |
|---|---|---|---|
| Core model | Message broker (push) | Distributed log (pull) | Hybrid broker + log |
| Message lifecycle | Pushed → acked → deleted | Appended → retained by policy | Cursor-tracked in ledger |
| Replay capability | None after ack | Full via offset reset | Full via cursor reset |
| Storage architecture | Coupled to broker | Coupled (partitions on disk) | Separated (BookKeeper ledgers) |
| Scaling model | Add brokers | Add brokers + rebalance partitions | Scale compute and storage independently |
| Operational complexity | Low-medium | Medium-high | High (broker + BookKeeper + ZooKeeper) |
The Decision Tree That Actually Matters
- Do consumers need to replay messages? No → RabbitMQ is likely sufficient and simpler. Yes → continue.
- Do multiple independent consumers need the same stream? Yes → Kafka or Pulsar. No → still consider Kafka for durability, but RabbitMQ may work.
- Do you need to scale storage independently of compute? Yes → Pulsar's architecture wins. No → Kafka's simpler operational model is worth the coupling.
- What's your team's operational capacity? Running BookKeeper + Pulsar brokers is meaningfully harder than Kafka with KRaft. Small platform teams should weight this heavily.
The Pulsar Nuance
Pulsar's compute/storage separation via BookKeeper follows the same disaggregated pattern winning in modern databases — architecturally elegant and theoretically superior for independent scaling. But the operational tax is real: you're now running and monitoring BookKeeper clusters alongside brokers, and Pulsar still requires ZooKeeper. Meanwhile, Kafka's KRaft mode has eliminated its ZooKeeper dependency, meaningfully closing the operational simplicity gap.
The most common anti-pattern: teams choosing Kafka because it's the default, then using it as a task queue with competing consumers and no replay — paying Kafka's operational complexity for RabbitMQ's use case.
What to do
Audit your current messaging system's actual consumption patterns this sprint — specifically check whether consumers use replay, or if you're running Kafka as a glorified task queue
If evaluating Pulsar, run a proof-of-concept specifically testing independent storage scaling and mixed queue/streaming workloads against your Kafka baseline before committing
Document your messaging system decision rationale in an ADR (Architecture Decision Record) tied to your actual workload characteristics, not feature matrices