Difference between Kafka and RabbitMQ
When applications need to exchange messages, Apache Kafka and RabbitMQ are two of the most popular choices. Both move data between systems, but they are built on very different ideas and shine in different situations.
This guide compares them side by side: how they store and route messages, how consumers receive them, ordering, scaling and reliability, with Spring Boot code for both, an e-commerce example and clear advice on when to choose each.
1. Kafka and RabbitMQ at a Glance
The simplest way to remember the difference:
- Kafka is like a newspaper archive. Every article is written into an ordered record and kept for a set time. Any number of readers can read it, at their own pace, and come back to old articles later.
- RabbitMQ is like a post office. Each letter is sorted and delivered to the right mailbox, picked up by a recipient, and then it is gone.
Kafka (distributed log)
Producer --> [ 0 | 1 | 2 | 3 | 4 | 5 ] topic partition (kept for days)
^ ^
Consumer A Consumer B (each tracks its own position)
RabbitMQ (message broker with queues)
Producer --> [ Exchange ] --routing--> [ Queue ] --> Consumer
message removed after acknowledgement
2. What Is Apache Kafka?
Apache Kafka is a distributed event streaming platform designed to handle very high volumes of data in real time. It stores messages in an ordered, append-only log, split into partitions spread across brokers. Consumers read at their own pace and can re-read old messages.
- Typical uses: real-time analytics, event-driven microservices, event sourcing, log and metrics collection, large data pipelines.
- Message storage: kept on disk for a configurable time, whether or not they have been read, so many consumers can read them independently.
- Performance: very high throughput, often hundreds of thousands to millions of messages per second on a cluster.
Learn more in Kafka Introduction and Kafka Architecture.
3. What Is RabbitMQ?
RabbitMQ is a traditional message broker built around queues. Producers send messages to an exchange, which routes them to one or more queues using flexible rules; consumers receive messages from those queues and acknowledge them.
- Typical uses: task and job queues, background processing, request–reply between services, workflows that need complex routing.
- Message storage: a message is normally removed from its queue once a consumer acknowledges it.
- Performance: good throughput, typically tens of thousands of messages per second per node, with very low latency and strong per-message delivery control.
- Protocols: AMQP (its main protocol), plus MQTT and STOMP, which suits IoT and many programming languages.
4. Key Differences
| Feature | Kafka | RabbitMQ |
|---|---|---|
| Architecture | Distributed, partitioned, append-only log | Broker with exchanges and queues |
| Message retention | Kept for a configured time or size, even after being read | Removed from the queue after acknowledgement |
| Replay | Yes: consumers can re-read old messages | Not with classic queues; possible with RabbitMQ Streams |
| Delivery model | Pull: consumers fetch messages | Push: the broker sends messages to consumers (pull is also possible) |
| Routing | Simple: producers choose a topic; keys pick partitions | Rich: direct, topic, fanout and headers exchanges |
| Ordering | Guaranteed per partition | Guaranteed per queue with a single consumer |
| Throughput | Very high; built for large-scale streaming | Good; optimized for flexible, reliable delivery |
| Latency | Low, but tuned for batching | Very low for individual messages |
| Scaling consumers | Up to one consumer per partition in a group | Add consumers to a queue freely (competing consumers) |
| Per-message features | Few: no priorities or per-message TTL | Priorities, per-message TTL, dead-letter exchanges, delayed messages (plugin) |
| Stream processing | Built-in ecosystem: Kafka Streams, Kafka Connect | Not built in; use external tools |
| Best for | Event streaming, analytics, event sourcing | Task queues, background jobs, complex routing |
5. Log vs Queue: How Messages Are Stored
5.1 Kafka: a log
Kafka appends every message to the end of a partition log and assigns it an offset. Reading does not remove anything. Each consumer group remembers its own offset, so one group can be at offset 5,000 while another is replaying from offset 0. Data is removed only by retention rules, such as “keep 7 days”.
5.2 RabbitMQ: queues
RabbitMQ holds messages in queues until a consumer receives and acknowledges them, then deletes them. Queues are designed to stay short: messages flow through quickly. If many messages pile up, RabbitMQ is doing more work than it was designed for.
| RabbitMQ queue type | Description |
|---|---|
| Classic queues | The original queue type; simple and fast |
| Quorum queues | Replicated across nodes using the Raft protocol; the recommended choice for important, durable data |
| Streams | An append-only log, similar to Kafka, with retention and replay; available since RabbitMQ 3.9 |
6. How Messages Are Routed
Kafka routing is simple: the producer chooses a topic, and the message key decides the partition. Consumers subscribe to topics. Any filtering happens in the consumer.
RabbitMQ routing is one of its strongest features. Producers send to an exchange, and bindings decide which queues receive each message:
| Exchange type | How it routes | Example |
|---|---|---|
| Direct | To queues whose binding key exactly matches the routing key | payment.failed goes only to the payments queue |
| Topic | By pattern: * matches one word, # matches zero or more | order.*.eu matches order.created.eu |
| Fanout | To every bound queue, ignoring the routing key | Broadcast a cache-refresh signal |
| Headers | By matching message header values | Route on region=eu and type=invoice |
7. Push vs Pull: How Consumers Receive Messages
| Kafka (pull) | RabbitMQ (push) | |
|---|---|---|
| How it works | Consumers call poll() to fetch batches | The broker pushes messages to subscribed consumers |
| Flow control | Each consumer reads at its own speed | A prefetch limit controls how many unacknowledged messages a consumer gets |
| Slow consumers | Simply fall behind (lag grows) and catch up later | Messages wait in the queue; long queues use memory |
| Tracking progress | Consumer commits an offset per partition | Consumer acknowledges each message (ack, nack or reject) |
8. Ordering and Scaling
8.1 Ordering
- Kafka guarantees order within a partition. Messages with the same key go to the same partition, so all events of one order stay in order, even with many consumers.
- RabbitMQ delivers a queue’s messages in order, but with several competing consumers they may be processed out of order, and redeliveries after failures can change the order. Strict ordering usually means one consumer per queue, or RabbitMQ’s single-active-consumer feature.
8.2 Scaling
- Kafka scales by adding partitions and brokers. Within a consumer group, the number of partitions limits how many consumers can work in parallel.
- RabbitMQ scales consumers easily: just add more consumers to a queue. Scaling a single very busy queue across nodes is harder, though quorum queues, streams and sharding options help.
9. Delivery Guarantees and Reliability
Both can be configured for at-least-once delivery, the most common choice, where a message may occasionally be delivered twice but is not lost.
| Concern | Kafka | RabbitMQ |
|---|---|---|
| Durable storage | Replication across brokers (replication factor 3) | Quorum queues replicated across nodes |
| Producer confirmation | acks=all | Publisher confirms |
| Consumer confirmation | Commit offsets after processing | Manual acknowledgements after processing |
| Duplicate protection | Idempotent producer; transactions for exactly-once within Kafka | Idempotent consumers (deduplicate by message ID) |
| Failed messages | Retry topics and dead-letter topics (built by the application or framework) | Dead-letter exchanges built in |
See Kafka Fault Tolerance for Kafka’s replication in detail.
10. Kafka in Spring Boot: Code Example
With Spring for Apache Kafka (spring-kafka), sending and receiving events takes only a few lines:
spring:
kafka:
bootstrap-servers: localhost:9092
producer:
acks: all
consumer:
group-id: analytics-service
auto-offset-reset: earliest
package com.example.shop.kafka;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Service
class PageViewPublisher {
private final KafkaTemplate<String, String> kafka;
PageViewPublisher(KafkaTemplate<String, String> kafka) {
this.kafka = kafka;
}
void pageViewed(String userId, String productId) {
// Key = user ID: all events of one user stay in order in one partition
kafka.send("page-views", userId, "{\"userId\":\"" + userId + "\",\"productId\":\"" + productId + "\"}");
}
}
@Component
class AnalyticsListener {
// Each consumer group receives every event independently
@KafkaListener(topics = "page-views", groupId = "analytics-service")
void onPageView(String event) {
System.out.println("Updating dashboards with " + event);
}
}
@Component
class RecommendationListener {
@KafkaListener(topics = "page-views", groupId = "recommendation-service")
void onPageView(String event) {
System.out.println("Updating recommendations with " + event);
}
}
Both listeners receive every page view, because they belong to different consumer groups. A new service added next month can even read last week’s events, as long as they are still within the retention period.
11. RabbitMQ in Spring Boot: Code Example
With Spring AMQP (spring-boot-starter-amqp), you declare the exchange, queue and binding, then send and receive:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
listener:
simple:
acknowledge-mode: auto # ack after the listener returns, nack on exception
prefetch: 10 # at most 10 unacknowledged messages per consumer
default-requeue-rejected: false # failed messages go to the dead-letter exchange
package com.example.shop.rabbit;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Configuration
class RabbitConfig {
@Bean
TopicExchange ordersExchange() {
return new TopicExchange("orders");
}
@Bean
Queue paymentQueue() {
return QueueBuilder.durable("order-payments")
.quorum() // replicated queue
.deadLetterExchange("orders.dlx") // failed messages go here
.build();
}
@Bean
Binding paymentBinding(Queue paymentQueue, TopicExchange ordersExchange) {
// Receive every "order.created.*" message, for any region
return BindingBuilder.bind(paymentQueue).to(ordersExchange).with("order.created.*");
}
}
@Service
class OrderPublisher {
private final RabbitTemplate rabbit;
OrderPublisher(RabbitTemplate rabbit) {
this.rabbit = rabbit;
}
void orderCreated(String orderId, String region) {
rabbit.convertAndSend("orders", "order.created." + region, orderId);
}
}
@Component
class PaymentWorker {
// Run several instances: each message is processed by exactly one of them
@RabbitListener(queues = "order-payments")
void process(String orderId) {
System.out.println("Processing payment for order " + orderId);
}
}
Each order goes to one payment worker, even when several are running, and is removed from the queue once processed. If the worker throws an exception, the message is rejected and, because default-requeue-rejected is false, moved to the dead-letter exchange instead of being retried forever. Add a retry policy if you want a few attempts first.
12. Example: An E-Commerce Application
Imagine an online shop that uses both tools for what each does best:
- Kafka: every user activity, such as page views, searches, clicks and purchases, is sent to Kafka. The recommendation engine, analytics dashboards and fraud detection all read these events independently, and a new data-science team can replay last week’s events to train a model.
- RabbitMQ: when a customer places an order, a task is sent to RabbitMQ. One worker picks it up to process the payment, another creates a PDF invoice, and failed tasks are retried or moved to a dead-letter queue, so each order is handled exactly by one worker, reliably.
User activity --> [ Kafka: page-views, orders ] --> Analytics, Recommendations, Fraud
(each reads every event, can replay)
Order placed --> [ RabbitMQ: orders exchange ] --> payment queue --> Payment workers
--> invoice queue --> Invoice workers
(each task handled once, then removed)
13. When to Choose Kafka
- You need very high throughput, such as clickstreams, logs, metrics or IoT data.
- Many independent consumers must read the same events.
- You need to replay history, for example to rebuild a database or train a model.
- You are building event-driven microservices or event sourcing.
- You need stream processing (Kafka Streams) or data integration (Kafka Connect).
- Ordering per key matters at scale.
14. When to Choose RabbitMQ
- You need a task or job queue where each job is done once by one worker.
- You need complex routing by patterns or headers.
- You need per-message features: priorities, per-message expiry (TTL), delayed delivery or request–reply.
- Message volumes are moderate, and you want very low latency for each message.
- You need protocols such as AMQP, MQTT or STOMP, for example for IoT devices.
- You want a broker that is simple to start with for a small team.
15. Using Kafka and RabbitMQ Together
Many organizations run both. A common pattern:
- Kafka is the central event backbone: every important business event is published there, kept and available to any team.
- RabbitMQ handles work distribution inside a service or team: background jobs, retries with delays, and routing tasks to the right workers.
Connectors, such as Kafka Connect connectors for RabbitMQ, can move messages between the two when needed. Avoid running both without a clear reason, though: each adds operational work.
16. Common Myths
| Myth | Reality |
|---|---|
| “RabbitMQ is not reliable.” | With quorum queues, publisher confirms and manual acknowledgements, RabbitMQ is very reliable |
| “Kafka is just a faster RabbitMQ.” | They have different models: a log for streaming versus queues for task distribution |
| “Kafka can’t be used as a queue.” | Consumer groups give queue-like work sharing, but per-message acknowledgements, priorities and retries need extra work |
| “RabbitMQ can never replay messages.” | RabbitMQ Streams add a replayable log since version 3.9 |
| “Kafka always needs ZooKeeper.” | Modern Kafka uses KRaft; Kafka 4.0 removed ZooKeeper entirely |
17. Summary
In simple words:
- Use Kafka when you need high throughput, real-time event streaming, long retention and the ability for many consumers to read and replay the same events independently.
- Use RabbitMQ when you need reliable task queues, flexible routing, per-message features such as priorities and delays, and traditional queue-based communication between services.
Both are powerful, mature and reliable when configured well. The right choice depends on whether your problem is mainly streaming events to many readers (Kafka) or distributing work to the right worker (RabbitMQ), and many systems use both.
18. Frequently Asked Questions (FAQ)
Q1. What is the main difference between Kafka and RabbitMQ?
Kafka is a distributed log: messages are stored in order and kept for a set time, and many consumers can read and re-read them independently.
RabbitMQ is a message broker with queues: messages are routed to queues, delivered to a consumer and removed once acknowledged. Kafka suits event streaming; RabbitMQ suits task queues and flexible routing.
Q2. Which is faster, Kafka or RabbitMQ?
It depends on what “faster” means:
- For throughput, the total number of messages per second, Kafka is usually much higher, thanks to batching, sequential disk writes and partitioning.
- For latency of individual messages at moderate load, RabbitMQ is often very fast, because it pushes each message straight to a consumer.
Both are fast enough for most applications; choose based on the messaging model you need.
Q3. Can Kafka replace RabbitMQ?
Sometimes. Kafka consumer groups can share work like a queue, so simple background processing can run on Kafka. But Kafka lacks several RabbitMQ features out of the box:
- Per-message acknowledgements and redelivery of single messages.
- Message priorities and per-message expiry.
- Flexible routing by patterns or headers.
- Built-in delayed delivery and dead-lettering.
If you rely on these, RabbitMQ is usually the better fit.
Q4. Can RabbitMQ replace Kafka?
For moderate volumes, partly. RabbitMQ Streams, available since version 3.9, add an append-only log with retention and replay, similar to Kafka topics.
For very high throughput, long retention of large data sets, stream processing with Kafka Streams, or the large Kafka Connect ecosystem, Kafka remains the stronger choice.
Q5. Is Kafka a message queue?
Not in the traditional sense. Kafka is an event streaming platform built on a distributed log. Messages are not removed when read, and every consumer group gets every message.
You can get queue-like behavior, where each message is handled by one consumer, by using a single consumer group, but the underlying model is a log, not a queue.
Q6. Does RabbitMQ delete messages after they are consumed?
Yes, in classic and quorum queues. Once a consumer acknowledges a message, RabbitMQ removes it. If the consumer rejects it or disconnects without acknowledging, the message is requeued or sent to a dead-letter exchange.
RabbitMQ Streams are the exception: they keep messages according to retention rules, like Kafka.
Q7. Which one guarantees message ordering?
- Kafka guarantees order within each partition. Messages with the same key always go to the same partition, so they stay in order even with many consumers.
- RabbitMQ keeps order within a queue, but with several competing consumers or redeliveries, processing order is not guaranteed. Use a single consumer, or the single-active-consumer option, for strict ordering.
Q8. Which is more reliable?
Both can be very reliable when configured properly:
- Kafka: replication factor 3,
min.insync.replicas=2,acks=all, idempotent producers and offsets committed after processing. - RabbitMQ: quorum queues, persistent messages, publisher confirms and manual acknowledgements.
Reliability problems usually come from unsafe settings, not from the tool itself.
Q9. Which is easier to learn and operate?
Many teams find RabbitMQ easier to start with: a single node, a management web interface, and simple concepts for basic queues.
Kafka has more concepts to learn, such as partitions, offsets, consumer groups and replication, and running a production cluster takes more care. KRaft has made Kafka simpler by removing ZooKeeper, and managed cloud services remove most operational work for both.
Q10. Which is better for microservices?
Both are widely used, for different jobs:
- Kafka for events that several services react to, such as
OrderPlaced, especially when you want history and replay. - RabbitMQ for commands and tasks sent to one service, such as “generate this invoice”, and for request–reply.
Pick based on the communication pattern, not on popularity.
Q11. What is a RabbitMQ exchange, and does Kafka have one?
An exchange receives messages from producers and routes them to queues using bindings. RabbitMQ has four types: direct, topic, fanout and headers.
Kafka has no exchanges. Producers write directly to a topic, and the message key decides the partition. Any filtering or routing logic happens in consumers or in stream processing, such as Kafka Streams.
Q12. Can consumers replay old messages?
- Kafka: yes. Consumers can reset their offsets, for example to the beginning or to a timestamp, and read messages again, as long as they are within retention.
- RabbitMQ: not with classic or quorum queues, because consumed messages are deleted. RabbitMQ Streams do support replay from an offset or timestamp.
Q13. Does RabbitMQ support message priorities and delays?
Yes. RabbitMQ supports priority queues, per-message and per-queue TTL (expiry), dead-letter exchanges, and delayed delivery through a plugin or a TTL plus dead-letter pattern.
Kafka has no built-in message priorities or per-message delays. These must be built in the application, for example with separate topics for different priorities or retry delays.
Q14. How do Kafka and RabbitMQ handle failed messages?
- RabbitMQ: a consumer can reject a message; with
requeue=falseit goes to a dead-letter exchange, which is built in. - Kafka: there is no per-message rejection. Frameworks such as Spring for Apache Kafka retry the message and then publish it to a dead-letter topic, so the partition can continue.
Q15. How do they scale differently?
- Kafka scales with partitions and brokers. More partitions allow more parallel consumers in a group; more brokers add storage and throughput.
- RabbitMQ scales consumers easily by adding them to a queue, and scales the cluster with more nodes. A single extremely busy queue is harder to scale, though streams and sharding help.
Q16. What protocols do Kafka and RabbitMQ use?
- Kafka uses its own binary protocol over TCP, with official and community clients for many languages.
- RabbitMQ uses AMQP as its main protocol, and also supports MQTT and STOMP, plus its own stream protocol for streams.
RabbitMQ’s MQTT support makes it a common choice for IoT devices.
Q17. How do I use Kafka and RabbitMQ in Spring Boot?
- Kafka: add
spring-kafka; send withKafkaTemplateand receive with@KafkaListener. - RabbitMQ: add
spring-boot-starter-amqp; send withRabbitTemplateand receive with@RabbitListener.
kafkaTemplate.send("page-views", userId, event); // Kafka
rabbitTemplate.convertAndSend("orders", "order.created.eu", id); // RabbitMQ
Spring Boot configures both from application.yml.
Q18. Should I use both Kafka and RabbitMQ in one system?
It can make sense in larger systems: Kafka as the company-wide event backbone, and RabbitMQ for task distribution inside services. Each tool then does what it is best at.
For smaller systems, running two messaging platforms doubles the operational work. Start with the one that fits your main need, and add the other only when there is a clear reason.
Q19. How do I try Kafka and RabbitMQ locally?
Docker is the quickest way:
# Kafka (single node, KRaft mode)
docker run -d --name kafka -p 9092:9092 apache/kafka:latest
# RabbitMQ with the management web UI at http://localhost:15672 (guest / guest)
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management
Then run the Spring Boot examples from this tutorial against them.
Q20. How do I decide quickly which one to use?
Ask one question: do many consumers need to read the same stream of events, possibly again later?
- Yes: choose Kafka.
- No, each message is a task for one worker, possibly with routing, priorities or delays: choose RabbitMQ.
Then check volume: very high, continuous data favors Kafka; moderate volumes with rich delivery features favor RabbitMQ.