Choosing Your Message Queue in 2025: Developer Insights on Kafka, RabbitMQ, NATS, and More

May 24, 2025

The choice of a message queue in modern distributed architectures is a complex one, with a plethora of options each carrying its own set of trade-offs. A recent Hacker News discussion delved into what developers are choosing for their systems in 2025, revealing valuable insights, war stories, and regrets.

Key Themes: Queues vs. Streams and Operational Simplicity

A fundamental point raised multiple times is the distinction between queues and streams.

  • Queues (like SQS, traditional RabbitMQ usage, Beanstalkd) typically involve a message being consumed once by a single worker. They are well-suited for background jobs like sending a registration email. However, if multiple services need to react to the same event, this can lead to tight coupling as new queues must be added for each interested service.
  • Streams (like Kafka, NATS Jetstream, Redis Streams) allow messages (or events) to be consumed multiple times by different consumer groups. This promotes loose coupling, as services can subscribe to event streams (e.g., 'user_registered') independently. Streams often offer replayability, allowing new services to process historical data or existing services to recover from errors by re-processing messages.

Operational simplicity is another major consideration. Many developers lean towards solutions that are easy to set up and maintain, especially for smaller projects or teams without dedicated operations staff.

Popular Choices and Developer Experiences

Here's a breakdown of commonly mentioned message queues and the community's take on them:

  • Kafka (and variants like Redpanda, AWS MSK):

    • Pros: Highly scalable, persistent, offers replayability, supports multiple consumers on the same topic. Ideal for event sourcing, high-throughput scenarios, and as a central nervous system for microservices. Managed services (Confluent Cloud, MSK) can ease operational burdens.
    • Cons: Operationally complex to self-host. Steeper learning curve for its programming model. One user noted issues with data type handling in MSK. As one commenter put it, "If you're going to use it you should fully commit to building your whole system on it and accept that you will need to invest in ops at least a little."
  • RabbitMQ:

    • Pros: Mature, reliable, feature-rich (e.g., intelligent routing, priority queues). Considered a good alternative to Kafka for moderate scale without extreme replayability needs. One user highlighted its reliability and low maintenance in production for years.
    • Cons: Some users reported negative experiences with clustering (split-brain issues, clients not receiving messages).
  • NATS.io:

    • Pros: Lightweight, high-performance, and flexible. Can be embedded in Go applications for simple deployments. Core NATS offers ephemeral pub/sub, while Jetstream adds durable, Kafka-like streaming capabilities. Praised for its ease of management and powerful filtering.
    • Cons: A 10MB maximum message size was mentioned as a potential limitation, sometimes requiring custom chunking.
  • Redis Streams:

    • Pros: Operationally simple, especially if Redis is already in use. Good performance. Easy to write consumers in various languages.
    • Cons: Durability might be less robust than Kafka for some critical use cases.
  • SQS (AWS):

    • Pros: Very simple to use if already in the AWS ecosystem. Managed, reliable, and "gets out of your way." Great for basic job queues.
    • Cons: Purely a queue; lacks streaming features like replayability or multiple independent consumers for the same message.
  • Postgres (or other DB-based queues):

    • Pros: Simplest option for basic needs, leveraging existing infrastructure. Can keep stack minimal. One user reported handling ~70k messages/second.
    • Cons: Scales "until it doesn't." Can become a performance bottleneck for the main database. Implementing stream semantics is challenging. Not a dedicated, optimized queuing solution.
  • Other Noteworthy Mentions:

    • Beanstalkd: Praised for being small, fast, and simple to deploy (e.g., apt-get on Debian).
    • Pulsar: Mentioned for its elegant modular design, open-source ecosystem, and performance comparable to Kafka.
    • ZeroMQ: Viewed more as a building block for custom messaging solutions, with excellent documentation for understanding messaging patterns.
    • Google PubSub & AWS Kinesis: Cloud-specific managed services offering robust features. Kinesis was chosen over Kafka by one team for simpler operations when full persistence wasn't needed.
    • Sidekiq (Ruby/Rails): A popular choice in the Ruby ecosystem, often backed by Redis.

Regrets and Lessons Learned

  • Complexity: Adding a complex system like Kafka for simple job queues was a common regret. Starting simple (e.g., with Postgres or SQS) and evolving as needed is often wiser.
  • Data Loss: Reliance on non-replayable queues led to data loss in some scenarios, highlighting the value of Kafka's replayability for critical messages.
  • Scalability of DB Queues: While DB-based queues can work, developers acknowledged their limits. One user advised, "I personally would avoid these, unless you have a compelling reason to use it."
  • Alternatives: One commenter pointed out that sometimes Workflow Engines are a better fit than queues, especially for tasks with longer processing times.

Conclusion

The discussion underscores that there's no single "best" message queue. The ideal choice hinges on the specific requirements of the project: the scale of data, the need for persistence and replayability, the desired level of coupling between services, the team's operational capacity, and existing infrastructure. Understanding the fundamental differences between simple queues and event streams is crucial for making an informed decision. Many developers advocate for starting simple and only introducing more complex systems when genuinely necessary.

Get the most insightful discussions and trending stories delivered to your inbox, every Wednesday.