Most message queue comparisons read like spec sheets: throughput numbers, protocol lists, feature matrices. That's the wrong way to choose. The four main options — RabbitMQ, Kafka, Redis, and cloud pub/sub services — aren't four competitors for one job. They're four different tools that happen to share the word "queue" in their marketing.
I've run RabbitMQ in production for years powering a deployment pipeline, used Redis-backed queues for smaller job systems, and eventually moved background processing onto a managed cloud pub/sub. Each move was driven by a use-case mismatch, not by benchmarks. Here's the mental model I wish I'd had at the start.
What each one actually is
RabbitMQ: a smart broker for work distribution
RabbitMQ is a traditional message broker built around AMQP. Its defining feature is *routing intelligence in the broker*: exchanges route messages to queues by binding rules (direct, topic, fanout, headers), consumers acknowledge each message individually, and unacked messages get redelivered. It has first-class support for priorities, per-message TTLs, and dead-letter exchanges ([rabbitmq.com/docs](https://www.rabbitmq.com/docs)).
The model is destructive consumption: once a message is acked, it's gone. That's exactly right for task queues — "resize this image," "send this email," "deploy this app" — where each job should be handled once by one worker.
What it costs you: RabbitMQ is a stateful service you operate. Clustering and queue replication (quorum queues) work well but need understanding, and an unbounded queue during a consumer outage is a classic way to run a broker out of memory. Set max-length policies and alert on queue depth from day one.
Kafka: a distributed log, not a queue
Kafka stores an append-only, partitioned log. Messages aren't deleted on consumption — consumers track their own offset and can re-read from any point within the retention window ([kafka.apache.org/documentation](https://kafka.apache.org/documentation/)). Ordering is guaranteed per partition, and consumer groups let many services independently read the same stream.
That replay property is the whole point. If you need to feed the same events to a search indexer, an analytics pipeline, and a fraud detector — or reprocess last Tuesday because of a bug — Kafka is built for it. It's also the only option here designed for sustained very high throughput with long retention.
What it costs you: Kafka is the heaviest operational commitment on this list. Partitioning strategy, consumer rebalancing, retention tuning, and capacity planning are real ongoing work, even with KRaft removing ZooKeeper. Using Kafka as a simple background-job queue is the most common over-engineering I see: you take on log-management complexity to get semantics RabbitMQ gives you out of the box — and per-message acknowledgment of individual jobs is actually *awkward* in Kafka, because offsets commit in order.
Redis: the queue you already have
Redis does queues two ways: the old-school LPUSH/BRPOP list pattern, and Redis Streams, which adds consumer groups, per-message acknowledgment, and pending-entry tracking ([redis.io — Streams](https://redis.io/docs/latest/develop/data-types/streams/)). Libraries like BullMQ (Node.js) and Celery's Redis transport build full job-queue semantics — retries, backoff, delayed jobs, priorities — on top.
The pitch is operational simplicity: if Redis is already in your stack for caching, a job queue is one library away, with no new infrastructure. For the vast majority of web apps — email sends, thumbnail generation, webhook delivery, report generation — this is genuinely enough.
The caveat is durability. Redis persistence (RDB snapshots, AOF) is configurable but weaker by default than a disk-first broker; a crash can lose recent jobs depending on your fsync policy. Fine for "retry the webhook later," not fine for "this message represents money."
Cloud pub/sub: someone else's problem
Managed services — AWS SQS/SNS ([aws.amazon.com/sqs](https://aws.amazon.com/sqs/)), Google Cloud Pub/Sub ([cloud.google.com/pubsub/docs](https://cloud.google.com/pubsub/docs)) — give you queues with effectively unlimited scale, pay-per-use pricing, and zero servers. Dead-letter queues, retry policies, and at-least-once delivery are configuration checkboxes instead of architecture.
Having migrated a worker fleet from self-hosted RabbitMQ to a cloud pub/sub, the honest summary is: you trade features and control for the permanent removal of an entire category of pages. No more broker upgrades, no disk-full incidents, no cluster partition mysteries. The trade-offs are vendor lock-in, fewer routing primitives than AMQP, and latency that's good but not Redis-good.
Choosing by use case
Background jobs for a web app (emails, image processing, exports): Redis + BullMQ/Celery if Redis is already deployed; RabbitMQ if you need priorities, complex routing, or stronger durability. Kafka is the wrong tool here.
Event streaming and analytics (clickstreams, audit logs, event sourcing, feeding multiple downstream systems): Kafka, clearly. Nothing else on this list does replay and multi-consumer fan-out with retention properly.
Microservice decoupling on a small team: cloud pub/sub. The moment your queue is load-bearing across services, its availability becomes your availability — and a managed service's uptime engineering beats what a two-person platform team can provide.
Task distribution with strict delivery control (per-message TTL, priority tiers, dead-lettering with requeue rules, competing consumers across heterogeneous workers): RabbitMQ. This is its home turf and it's still the best at it in 2026.
"We might need Kafka later": then use something simpler now. Migrating a job queue is a week of work; running Kafka you didn't need is a permanent tax.
The mistakes that actually hurt
Assuming exactly-once delivery. Every system here is at-least-once in practice (Kafka's transactional exactly-once applies within Kafka-to-Kafka pipelines, not to your side effects). Your consumers must be idempotent: dedupe on a message ID, use upserts, make the handler safe to run twice. This is non-negotiable regardless of which queue you pick.
No dead-letter strategy. A poison message that crashes its consumer will be redelivered forever, blocking everything behind it. Configure a DLQ and a max-delivery count before launch, and alert when the DLQ is non-empty.
Unbounded growth. Queues are buffers, not databases. Decide what happens when producers outrun consumers — drop, shed, back-pressure, or scale — before it happens at 3 a.m.
Choosing on throughput you'll never see. Most teams push hundreds of messages per second, not hundreds of thousands. At that scale, all four options are fast enough, and the deciding factors are operations, semantics, and what your team already knows.
A short decision path
- 1Already have Redis and just need jobs? → Redis + a mature job library.
- 2Need replay, multiple independent consumers, or event history? → Kafka (or a managed Kafka).
- 3Need rich routing, priorities, and per-message control? → RabbitMQ.
- 4None of the above strongly, and you'd rather not operate a broker? → Cloud pub/sub.
If you land on the Redis path, PandaStack offers managed Redis alongside Postgres, MySQL, and MongoDB — attach it to your app and the connection URL is injected automatically, so a BullMQ worker deploys like any other container. Worth a look at [pandastack.io](https://pandastack.io) if you'd rather not run the queue infrastructure yourself either.