Publish-subscribe (Pub/Sub) messaging is the backbone of modern event-driven architectures. Whether you are building microservices, real-time data pipelines, or IoT telemetry systems, choosing the right self-hosted Pub/Sub platform determines your system’s scalability, reliability, and operational overhead.

In this guide, we compare three leading open-source Pub/Sub platforms — NATS, RabbitMQ, and Apache Pulsar — examining their architectures, performance characteristics, deployment patterns, and operational trade-offs.

Architecture Comparison

NATS: Cloud-Native Messaging

NATS is a lightweight, high-performance messaging system designed for cloud-native and edge computing environments. Created by Derek Collison (formerly of TIBCO and VMware), NATS uses a simple subject-based publish/subscribe model with optional JetStream persistence layer.

Key architectural features:

  • Subject-based routing with wildcard support (orders.*, orders.*.created)
  • Clustered topology with automatic mesh discovery
  • JetStream adds persistent storage, consumers, and replay
  • Sub-millisecond latency, millions of messages per second

RabbitMQ: Enterprise Message Broker

RabbitMQ implements the Advanced Message Queuing Protocol (AMQP 0-9-1) and supports multiple protocols via plugins (MQTT, STOMP, AMQP 1.0). It uses exchanges, queues, and bindings for flexible message routing with guaranteed delivery.

Key architectural features:

  • Exchange-based routing (direct, topic, fanout, headers)
  • Queue mirroring and quorum queues for HA
  • Plugin ecosystem for protocol support and management
  • Mature tooling with management UI and CLI

Apache Pulsar: Cloud-Native Pub/Sub

Apache Pulsar separates compute (brokers) from storage (Apache BookKeeper) for independent scaling. It supports both Pub/Sub and queue-based consumption patterns in a single platform with built-in multi-tenancy and geo-replication.

Key architectural features:

  • Tiered storage (hot in BookKeeper, cold in S3/blob storage)
  • Topics partitioned across BookKeeper ledgers
  • Multi-tenant with built-in authentication and authorization
  • Pulsar Functions for lightweight stream processing

Feature Comparison Table

FeatureNATS (JetStream)RabbitMQApache Pulsar
ProtocolNATS, MQTT, WebSocketAMQP 0-9-1, MQTT, STOMPPulsar Protocol, Kafka, MQTT
Messaging ModelPub/Sub + QueueQueue + Pub/SubPub/Sub + Queue
PersistenceJetStream (built-in)Quorum Queues / MirroredBookKeeper + Tiered Storage
Max Throughput10M+ msg/sec50K-200K msg/sec1M+ msg/sec
LatencySub-millisecond1-5 ms2-10 ms
ClusteringMesh (auto-discovery)Mirrored / QuorumSeparate brokers + bookies
Multi-TenancyAccountsVirtual HostsNative (namespaces)
Geo-ReplicationLeaf Nodes / SuperclustersShovel / FederationBuilt-in geo-replication
Stream ProcessingJetStream consumersStreams pluginPulsar Functions
Management UInats-top, nats-boardBuilt-in Management UIPulsar Manager
Docker Imagenats:latestrabbitmq:managementapachepulsar/pulsar:latest
LicenseApache 2.0MPL 2.0Apache 2.0
GitHub Stars19,800+13,600+15,200+

Deployment with Docker Compose

NATS with JetStream

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: "3.8"
services:
  nats:
    image: nats:2.11-alpine
    ports:
      - "4222:4222"   # Client connections
      - "8222:8222"   # Monitoring HTTP
      - "6222:6222"   # Cluster routing
    command: >
      -js
      -sd /data
      -c /etc/nats/nats.conf
    volumes:
      - nats-data:/data
      - ./nats.conf:/etc/nats/nats.conf:ro
    deploy:
      resources:
        limits:
          memory: 512M

volumes:
  nats-data:

nats.conf:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
jetstream {
  store_dir: "/data"
  max_mem: 256Mb
  max_file: 1Gb
}

accounts: {
  SYS: { users: [{user: sys, password: syspass}] }
  APP: { users: [{user: app, password: apppass}] }
}

system_account: "SYS"

RabbitMQ with Management Plugin

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: "3.8"
services:
  rabbitmq:
    image: rabbitmq:4.0-management-alpine
    ports:
      - "5672:5672"   # AMQP
      - "15672:15672" # Management UI
    environment:
      RABBITMQ_DEFAULT_USER: admin
      RABBITMQ_DEFAULT_PASS: rabbitmq-secret
      RABBITMQ_DEFAULT_VHOST: /
    volumes:
      - rabbitmq-data:/var/lib/rabbitmq
      - ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  rabbitmq-data:

rabbitmq.conf:

1
2
3
4
5
6
7
8
# Enable quorum queues for HA
queue_master_locator = min-masters
# Enable default user
default_user = admin
default_pass = rabbitmq-secret
default_vhost = /
# Set disk free limit
disk_free_limit.absolute = 2GB

Apache Pulsar (Standalone Mode)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
version: "3.8"
services:
  pulsar:
    image: apachepulsar/pulsar:4.0.2
    ports:
      - "6650:6650"   # Pulsar protocol
      - "8080:8080"   # HTTP API
      - "8443:8443"   # HTTPS API
    command: >
      bin/pulsar standalone
      --advertised-address pulsar
    volumes:
      - pulsar-data:/pulsar/data
      - pulsar-conf:/pulsar/conf
    environment:
      PULSAR_MEM: "-Xms256m -Xmx512m"
    deploy:
      resources:
        limits:
          memory: 1G

volumes:
  pulsar-data:
  pulsar-conf:

Performance Benchmarks

Performance varies significantly based on message size, persistence requirements, and cluster topology:

MetricNATSRabbitMQApache Pulsar
Publish (1 KB, no persistence)11M msg/s85K msg/s1.2M msg/s
Publish (1 KB, persistent)3.5M msg/s45K msg/s800K msg/s
Subscribe (durable)8M msg/s60K msg/s900K msg/s
End-to-end latency0.3 ms2.1 ms4.5 ms
Disk usage (1M msgs, 1 KB)~1.2 GB~1.5 GB~2.0 GB
Cluster node count3-5 typical3-7 typical3 brokers + 3 bookies min

These figures come from independent benchmarking with comparable hardware (8-core, 32 GB RAM, NVMe SSD). Actual performance depends on workload patterns and configuration tuning.

When to Choose Each Platform

Choose NATS When:

  • You need the lowest possible latency (IoT, real-time gaming, financial trading)
  • Your architecture is cloud-native or edge-focused
  • You want simple operational overhead (single binary, auto-clustering)
  • Subject-based routing with wildcards fits your domain model
  • JetStream provides sufficient persistence guarantees

Choose RabbitMQ When:

  • You need AMQP compatibility or multi-protocol support
  • Your team has existing RabbitMQ experience
  • You require complex routing patterns (exchanges, bindings, dead-letter queues)
  • You need mature management tooling and monitoring
  • Message ordering and guaranteed delivery are critical

Choose Apache Pulsar When:

  • You need massive scale with independent compute/storage scaling
  • Multi-tenancy is a first-class requirement
  • You want built-in geo-replication without complex setup
  • Tiered storage (hot/cold separation) reduces infrastructure costs
  • You need both queue and Pub/Sub consumption models

Choosing the Right Pub/Sub Platform

Selecting a message broker is rarely a one-size-fits-all decision. Consider these operational factors before committing:

Team expertise matters more than raw benchmarks. RabbitMQ has the largest talent pool — most DevOps engineers have encountered it. NATS has a simpler learning curve but fewer practitioners. Pulsar requires understanding BookKeeper and tiered storage, adding operational complexity.

Message persistence requirements drive architecture. If you can tolerate occasional message loss, NATS core (without JetStream) is the fastest option. If you need guaranteed ordering and at-least-once delivery with replay, RabbitMQ quorum queues or Pulsar ledgers are the right choice.

Scaling patterns differ fundamentally. NATS and Pulsar scale horizontally with automatic partitioning. RabbitMQ scales vertically more easily (larger nodes) but horizontal scaling requires careful queue placement and federation planning.

Cloud vs. bare metal affects your choice. NATS excels in ephemeral cloud environments with dynamic scaling. Pulsar’s tiered storage makes it cost-effective for long-term message retention. RabbitMQ works well on both cloud VMs and bare metal but benefits from fast local disks for queue storage.

Why Self-Host Your Pub/Sub Platform?

Self-hosting a Pub/Sub platform gives you full control over message routing, data sovereignty, and cost optimization. Managed alternatives like AWS SNS/SQS, Google Pub/Sub, or Azure Service Bus charge per-message fees that compound rapidly at scale.

For organizations processing millions of events daily, self-hosted NATS or RabbitMQ on commodity hardware costs a fraction of managed services. You retain complete visibility into message flows, can implement custom monitoring, and avoid vendor lock-in to a specific cloud provider’s messaging API.

For compliance-heavy industries (finance, healthcare, government), self-hosting ensures message data never leaves your infrastructure. NATS and RabbitMQ both support TLS encryption, mutual authentication, and audit logging — critical for regulatory requirements.

Self-hosted Pub/Sub platforms also integrate seamlessly with existing infrastructure. NATS connects to edge devices and IoT sensors, RabbitMQ bridges legacy systems via AMQP or MQTT, and Pulsar provides a unified event backbone across Kubernetes clusters and on-premise data centers.

For container orchestration patterns, see our task queue comparison. For event-driven architectures, our Kafka UI tools guide covers management interfaces, and our event sourcing platforms comparison explores persistence patterns.

FAQ

What is the difference between Pub/Sub and message queues?

Pub/Sub (publish-subscribe) sends messages to topics that multiple subscribers can consume independently. Each subscriber receives a copy of the message. Message queues deliver each message to exactly one consumer from a shared queue, enabling workload distribution. NATS and Pulsar support both patterns; RabbitMQ primarily uses queue-based routing but supports Pub/Sub via fanout exchanges.

Can NATS replace RabbitMQ?

NATS can replace RabbitMQ for many use cases, especially where low latency and simplicity are priorities. However, NATS lacks RabbitMQ’s rich exchange types, dead-letter queue handling, and mature plugin ecosystem. If your application relies on AMQP-specific features or complex routing patterns, RabbitMQ remains the better choice. For new projects without protocol constraints, NATS JetStream is often simpler to operate.

Is Apache Pulsar production-ready for self-hosted deployment?

Yes, Apache Pulsar is production-ready and used by major companies including Yahoo, Verizon, and Tencent. However, self-hosted Pulsar requires more operational expertise than NATS or RabbitMQ. The separation of brokers and bookies means you manage two cluster types. Start with standalone mode for development, then graduate to a minimum 3-broker, 3-bookie cluster for production.

How does NATS JetStream compare to Kafka?

NATS JetStream provides persistent messaging with consumers, ack/nack semantics, and replay — similar to Kafka’s core features. However, Kafka has a larger ecosystem, more connectors (Kafka Connect), and better long-term storage with tiered storage. JetStream is lighter weight and easier to operate but has fewer third-party integrations. Choose JetStream for simplicity; choose Kafka for ecosystem breadth.

What are the hardware requirements for each platform?

NATS is the lightest: 1 CPU core and 256 MB RAM handles millions of messages. RabbitMQ recommends 2-4 CPU cores and 2-4 GB RAM per node for moderate workloads. Pulsar standalone mode needs 4+ CPU cores and 4-8 GB RAM. Production Pulsar clusters require separate broker nodes (4+ cores each) and bookie nodes (4+ cores with fast disks each).

How do I migrate from RabbitMQ to NATS or Pulsar?

Migration requires adapting your client code to the new protocol. For RabbitMQ to NATS, replace AMQP publish/subscribe with NATS subjects. For RabbitMQ to Pulsar, use Pulsar’s Kafka-compatible protocol layer as a transition. Plan a dual-write period where messages are sent to both systems, then gradually switch consumers. NATS provides a migration guide for AMQP users on their documentation site.