Narad - The message broker that fits in one binary β€” and one head

byβ€’
Durable message broker in a single Go binary. Produce, consume, ack over plain HTTP β€” no SDK, no ZooKeeper. Queues, fan-out, delayed delivery, replay, and one-call replication. Proven with 300M+ soaked messages, zero lost. Apache-2.0.

Add a comment

Replies

Best
Maker
πŸ“Œ
Hi PH πŸ‘‹ I'm a backend engineer who spent the last few months building Narad to learn distributed systems properly β€” and it grew into something I'd actually run. It's a durable message broker in one Go binary: you produce, consume, and ack over plain HTTP with curl, and deploying is a single Helm chart β€” the cluster metadata (Raft) lives inside the same binary, so there's no ZooKeeper or external anything. It's an AP system β€” no ordering guarantee, and the docs say so in paragraph two, not a footnote. Before calling it 1.0, I soaked 300M+ messages through a live cluster at 1,000/s with zero loss, ran a kill -9 chaos matrix, and benched 50k msg/s through the full flow. Every claim in the docs is verified against the code. My favorite part shipped a day after 1.0: replication as a pattern, not a subsystem. One API call creates a live copy of a topic, deliberately placed on different machines. No quorums, no new machinery. It's free and Apache-2.0. I'd love your questions. The launch post has the stories:

the no-SDK HTTP approach is super refreshing, especially for polyglot setups. one thing that would help us adopt it: a built-in dead letter queue with configurable retry policies, so failed messages don't have to be reimplemented on every consumer side.

 ŞengΓΌl β€” great question, and it's one I decided on purpose rather than by omission

Narad deliberately has no built-in retry engine, because retryΒ policyΒ is business logic: max attempts, backoff shape, which errors are retryable, where dead messages go β€” every team answers those differently, and a broker that hardcodes the answers becomes the thing you fight. What Narad gives you instead are three durable primitives β€” visibility leases, acks, and topics β€” that compose into every retry policy I know of, consumer-side, where you can see it and change it without a broker upgrade.

The full menu is documented here, and it's shorter than you'd expect:Β Β β€” a DLQ is literally just a topic you create (with the whole API available on it: alert on its depth, replay it, re-drive it after fixing the bug), bounded retries are aΒ delivery_countΒ field in your message envelope, and spaced backoff uses Narad's native delayed topics. The core pattern is ~10 lines of consumer code.

Your "reimplemented on every consumer side" concern is real though, and the honest answer to that isn't a broker feature β€” it's client SDKs. You can build one internally for your company that follows your specific retry methods.

If you try the patterns page and find a policy it can't express, tell me β€” that would genuinely change my mind about what belongs in the broker.

love that it's a single binary with no zookeeper pain. one thing that would push me to actually use this in prod: built in prometheus metrics and a ready to go grafana dashboard so i can see queue depth, lag, and consumer ack rates without wiring it up myself.

Β Ayfer β€” you're describing what's already in the box

Every node serves Prometheus metrics onΒ /metricsΒ out of the box, zero config. Your exact list: queue depth isΒ narad_consumer_lag_messagesΒ (per partition), ack rates come from the ack/nack/extend counters, and lag has two flavors β€” regular consumer lag plusΒ narad_fanout_due_lag_seconds, which exists because offset-lag is aΒ lyingΒ metric for delayed topics and I wanted the honest one.

And the repo ships a ready-to-import Grafana dashboard β€”Β ops/monitoring/grafana/Β β€” 14 panels: throughput, consumer backlog, errors & rejections, disk, storage fsync latency, CPU/memory. It's not a marketing artifact; it's the actual dashboard I stared at for the 47-hour, 170M-message soak before cutting 1.0.

The Monitoring page also has a copy-paste alert table (the "wake me up" thresholds) and a section on what the dashboards look likeΒ duringΒ a node failure, so you know which spikes are normal:Β 

If you import it and something's missing for your setup, open an issue β€” this is exactly the feedback I want.

Tried it over the weekend and the single binary setup is genuinely refreshing, no Zookeeper dance, just one command and it's running. Really impressed by how the replay feature works over plain HTTP without needing an SDK.

A HTTP-only broker without SDK lock-in is genuinely useful, nice work. One thing that would help a lot for production rollouts: a built-in dead-letter queue option when messages hit max retries or get rejected on consume, so failures don't just sit there silently. Pair it with a simple GET to peek at the DLQ contents and teams can debug poison messages without digging through logs.