Choosing a Moleculer Transporter: NATS, Redis, Kafka, TCP, or MQTT for Production Microservices
A decision guide for selecting a Moleculer transporter (NATS, Redis, Kafka, TCP, MQTT) based on latency, scalability, operational complexity, and feature requirements in production microservice architectures.
08 Aug 2025, 23:16 UTC

The Decision You Face
Moleculer microservices need a transporter to exchange events, requests, and node metadata across processes. The choice locks in latency characteristics, operational burden, and scaling limits for the life of the cluster. Pick wrong and you'll fight failover storms, silent message loss, or an ops team that can't debug the message layer.
Takeaway: Match the transporter to your existing infrastructure, latency budget, and team's operational capacity. For most greenfield projects, NATS gives the best latency-to-operations ratio; Redis makes sense if you already run Redis; Kafka fits event-sourcing workloads; TCP/gossip works only for small, single-datacenter clusters; MQTT serves edge/IoT scenarios.
Constraints That Narrow the Field
- Ops capacity: Can your team run and monitor a dedicated message broker (NATS, Kafka) or do you need zero-external-dependency (TCP)?
- Existing investments: Do you already operate Redis, Kafka, or MQTT brokers?
- Cross-datacenter needs: TCP/gossip fails across high-latency links; NATS, Kafka, and Redis support multi-DC with proper config.
- Service discovery: NATS, Redis, and TCP include built-in discovery; Kafka requires an external registry (Consul, etcd).
- Persistence & replay: Only Kafka (log) and NATS JetStream (streams) offer durable replay; default Redis pub/sub and TCP are fire-and-forget.
Transporter Comparison at a Glance
| Transporter | Typical Latency | Horizontal Scale | HA Model | Discovery | Persistence | Ops Complexity |
|---|---|---|---|---|---|---|
| NATS (official) | ~1–2 ms | Excellent | Native clustering | Built-in | Optional (JetStream) | Low |
| Redis (official) | ~2–5 ms | Good | Sentinel / Cluster | Built-in | Pub/sub (streams optional) | Medium |
| MQTT (community) | ~5–10 ms | Good | Broker-dependent | Limited | Broker-dependent | Medium |
| TCP (built-in) | ~1–3 ms | Limited (<50 nodes) | Gossip | Built-in | None | Low |
| Kafka (community) | ~5–15 ms | Excellent | Native replication | External required | Log (replay) | High |
Trade-offs in Practice
NATS — Default Choice for Greenfield
NATS clusters self-heal, support TLS and auth out of the box, and the official @moleculer/transporter-nats package tracks Moleculer core versions. JetStream adds durability but requires explicit stream creation (nats stream add ORDERS --subjects 'orders.>'). Without JetStream, delivery is at-most-once — acceptable for stateless request/response, risky for event sourcing.
Redis — Leverage Existing Infrastructure
If you already run Redis Sentinel or Cluster, the Redis transporter avoids a new broker. Enable useRedisStreams: true in options for durability; otherwise pub/sub is fire-and-forget. Watch for Redis memory pressure under high fan-out — each service instance subscribes to its own channel pattern.
TCP/Gossip — Only for Small, Single-DC Clusters
Zero external dependencies is attractive, but gossip protocol timeouts make cross-datacenter deployments unreliable. Node count above ~50 increases convergence time and network chatter. No persistence means rolling restarts lose in-flight messages.
Kafka — Event Sourcing and Replay
Community packages (moleculer-kafka, @moleculer/transporter-kafka) vary in maintenance. Verify compatibility with your Moleculer version before adoption. You'll need an external service registry (Consul, etcd) for node discovery. Operational burden: broker tuning, partition strategy, consumer group lag monitoring.
MQTT — Edge and Intermittent Connectivity
QoS 1/2 gives delivery guarantees over unreliable links. Broker choice (EMQX, Mosquitto, VerneMQ) dictates HA and persistence. Discovery is limited — consider pairing with a separate registry.
Concrete Implementation: NATS Transporter
Assumes Moleculer 0.14.x and @moleculer/transporter-nats@0.14.x. Run on any node that starts a Moleculer service (gateway, worker, etc.). Requires network access to NATS cluster on port 4222.
Install
npm install @moleculer/transporter-nats@0.14.x --save
Configure in moleculer.config.js
module.exports = {
transporter: "NATS",
transporterOptions: {
servers: ["nats://nats-cluster:4222"],
maxReconnectAttempts: -1,
reconnectTimeWait: 2000,
// Enable JetStream for durability (requires NATS 2.10+ server)
// jetstream: true,
// streamName: "MOLECULER",
},
// Ensure unique node IDs across all instances
nodeID: process.env.NODE_ID || require('os').hostname() + '-' + process.pid
};
Permissions: The Node process needs outbound TCP to the NATS servers. If NATS requires auth, add user and pass (or token) to transporterOptions.
Validate Cross-Node Discovery
- Start three service instances across separate hosts or containers with the same NATS cluster.
- Attach to one instance's REPL:
moleculer-runner --repl --config moleculer.config.js - Run
broker.nodes.list()— all three nodes should appear within 5 seconds.
Validation Checklist for Production Readiness
- Node convergence: Start 3+ instances; confirm
broker.nodes.list()shows all nodes within 5 s. - Load latency: Fire 1,000 req/sec with
hey -n 10000 -c 50 http://gateway:3000/api/action; measure p99 latency. Expect p99 < 10 ms for NATS on same network. - Failover: Kill one NATS server (
kubectl delete pod nats-0orsystemctl stop nats); confirm Moleculer reconnects and node list stabilizes < 2 s. - Queue depth: Under load, check
broker.metricsfor transporter queue depth — sustained growth indicates backpressure.
Limitations and Cautions
- NATS JetStream requires explicit stream configuration on the server; default NATS is at-most-once.
- Redis transporter uses pub/sub by default; enable
useRedisStreams: truefor durability. - TCP/gossip does not support cross-datacenter reliably due to gossip timeouts.
- Kafka community packages vary in maintenance; verify compatibility with your Moleculer version before adoption.
- Duplicate
NODE_IDacross instances causes silent message loss — enforce uniqueness via env or orchestration.
Ongoing Verification
- Confirm installed version matches core:
npm ls @moleculer/transporter-nats(run in service project root). - Health endpoint (if using
@moleculer/web):curl http://localhost:3000/health/transporter. - NATS connectivity:
nc -z nats-cluster 4222andnats-server -c /etc/nats/server.conf -Vfor server version. - Review Moleculer changelog for transporter breaking changes: https://github.com/moleculerjs/moleculer/blob/master/CHANGELOG.md
How to Check the Result
After deployment, run the validation checklist weekly and after any version upgrade. Correlate p99 latency with transporter choice in your dashboards. If p99 drifts above 20 ms on NATS, investigate NATS server CPU, network saturation, or client reconnect storms.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.