# NSQ: A Decentralized Go Message Queue With No Broker to Babysit

> NSQ is a realtime distributed messaging platform written in Go, built around independent nsqd instances and a lookup service instead of a central broker. This review covers what it solves, how the pieces fit together, where it breaks down, and how it compares to Kafka and RabbitMQ.

**nsqio/nsq** — A realtime distributed messaging platform

- Repository: https://github.com/nsqio/nsq
- Website: https://nsq.io
- Stars: 25,779 · Forks: 2,887
- Language: Go
- License: MIT
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/nsqio-nsq

## The problem NSQ solves: message queues without a coordinator

Most message queues put a broker in the middle. Producers connect to it, consumers connect to it, and its health determines whether your system moves data. That design gives you ordering and retention, and it also gives you a component you have to size, replicate and fail over. NSQ takes the opposite position. The README describes it as promoting "distributed and decentralized topologies without single points of failure", which is a design statement, not a marketing line: the repository layout backs it up with separate top-level directories for nsqd, nsqlookupd and nsqadmin, each compiled into its own binary.

The target user is an engineer running a Go or Python service that needs to hand work to another service and does not want to operate a cluster with its own consensus layer. The README states that all parameters are specified on the command line and that the compiled binaries have no runtime dependencies. That means a deploy is a binary plus a flag list, not a JVM heap plan and a config file hierarchy. If you have ever spent a week tuning a broker's replication factor, that distinction is the whole pitch.

It is a poor fit for teams who need the queue to be the system of record. NSQ is a delivery mechanism. The README is explicit that it is agnostic to data format, so messages can be JSON, MsgPack, Protocol Buffers or anything else, which also means NSQ will not validate, index or query them for you.

## How nsqd, nsqlookupd and nsqadmin divide the work

The architecture has three moving parts. nsqd is the daemon that receives, queues and delivers messages to consumers. nsqlookupd is a discovery service that tracks which nsqd instances exist and what topics they carry. nsqadmin is a web UI for inspecting the cluster. The Dockerfile exposes ports 4150 and 4151 for nsqd, 4160 and 4161 for nsqlookupd, and 4170 and 4171 for nsqadmin, with the 1-suffixed port in each pair being the HTTP interface.

A producer can talk to nsqd directly or ask nsqlookupd where a topic lives. A consumer asks nsqlookupd for the nsqd instances publishing a topic, then connects to each one. Because discovery is a lookup rather than a routing layer, nsqlookupd going down does not stop existing consumers from receiving messages; it stops new consumers from finding producers. That is a meaningfully different failure mode from a broker outage, and it is the reason the README can claim no single point of failure without qualification.

The repository also ships a set of small utilities that reveal the intended workflow: nsq_to_file, nsq_to_http, nsq_to_nsq, nsq_tail, nsq_stat and to_nsq. nsq_tail lets you watch a topic from a terminal, and to_nsq pipes stdin into a topic. These are the tools you reach for before you write any client code, and their presence in the Makefile's APPS list means they build alongside the daemons.

## Installing NSQ and publishing your first message

The README points to binary releases for Linux, Darwin, FreeBSD and Windows, and to an official Docker image. The Dockerfile builds with CGO_ENABLED=0, so the resulting binaries are static. The image declares /data as the volume nsqd uses for persistent storage across restarts, and the comment in the Dockerfile notes that volumes must be configured explicitly with docker run -v.

If you build from source, the Makefile defines the install target that the Dockerfile itself invokes. The Dockerfile runs make with BLDDIR, PREFIX and BLDFLAGS set, which is the same target available to anyone with the repository checked out.

```bash
RUN CGO_ENABLED=0 make BLDDIR=/tmp/nsq PREFIX=/opt/nsq BLDFLAGS='-ldflags="-s -w"' install
```

The Makefile's install target creates the bindir under PREFIX and copies each built app into it. Running the default target builds the full APPS list, which the Makefile defines as nsqd, nsqlookupd, nsqadmin, nsq_to_nsq, nsq_to_file, nsq_to_http, nsq_tail, nsq_stat and to_nsq.

```bash
make
make install
```

Once the binaries are on your PATH, the README notes that all parameters are specified on the command line, so a running node is a binary plus flags rather than a config file. The Dockerfile is the only place in the repository that spells out the port assignments, and it does so with EXPOSE rather than with runtime flags, so the port numbers above are what the image declares rather than a documented default you can copy into a command.

## Where NSQ stops being the right tool

NSQ does not give you ordered, replayable log partitions. Topics and channels distribute messages across consumers rather than assigning each partition to one reader, so if your consumer needs to see every event for a given key in sequence, NSQ will not enforce that for you. Kafka's partition model does. This is not a gap NSQ plans to close; it is a consequence of choosing decentralized fan-out over a replicated log.

The README also carries a warning that deserves more weight than its placement suggests: "master is our development branch and may not be stable at all times." The most recent tagged release is v1.3.0 from 2023-12-27, while the repository's last push was on 2026-08-11. That gap between release and push means the code moving on master is not the code most users are running, and anyone building from source is opting into unreleased changes. Deploying from a git checkout rather than a tagged release is a real risk here, not a theoretical one.

Finally, the message delivery guarantee is at-least-once. A consumer that receives a message, processes it, and dies before acknowledging will see that message again. If your downstream operation is not idempotent, NSQ will duplicate work. The README frames the guarantee as reliable, which is accurate, but reliable and exactly-once are different promises.

## NSQ vs Kafka and RabbitMQ: the difference is who holds state

The related searches around NSQ are mostly comparisons, and the comparisons are fair because the three systems disagree about where state lives.

Kafka keeps messages in an append-only log with configurable retention, partitioned for ordered consumption and replicated across brokers. Its strength is replay: a new consumer can read history from the beginning. NSQ has no equivalent. Messages are delivered and forgotten, and retention beyond the in-memory queue depends on nsqd's disk-backed queue, which exists to survive restarts, not to serve historical reads. If you need to reprocess last week's events, Kafka is the tool and NSQ is not.

RabbitMQ routes through exchanges and bindings with a rich set of routing semantics, and it runs on Erlang with its own clustering model. NSQ has none of that routing vocabulary; the related search for "Nsq exchange" is a category error, since NSQ has topics and channels, not exchanges. What NSQ offers instead is a smaller operational surface: no Erlang runtime, no cluster formation protocol, and configuration entirely on the command line.

Neither comparison is a win or a loss in the abstract. Kafka wins on replay and ordering, RabbitMQ wins on routing flexibility, and NSQ wins on the number of things that can go wrong during a deploy.

## Licence, maintenance and the cost of upgrading

NSQ is MIT licensed. That is permissive: you can use it commercially, modify it, and redistribute it, provided the copyright notice and permission notice travel with it. The repository includes an AUTHORS file and a CODE_OF_CONDUCT.md, and the README credits Matt Reiferson and Jehiah Czebotar as the designers, with Bitly's support behind the original work. This is not legal advice; if your organisation has a policy on permissive licences, run the LICENSE file past whoever owns that policy.

Upgrade cost is low by the standards of messaging infrastructure. The go.mod lists a small dependency set, and the Dockerfile builds a static binary with CGO disabled, so there is no shared library to reconcile. The practical upgrade path is to replace the binary and restart, because all configuration lives on the command line. The catch is that command-line configuration means there is no migration script and no config schema version to check; if a flag changed between releases, you find out when the process fails to start.

The release cadence is slow. v1.2.0 landed in 2019, v1.2.1 in 2021, and v1.3.0 in 2023. The repository is not archived and the last push was on 2026-08-11, so work continues, but the gap between tags means you should read the ChangeLog.md before moving between them rather than assuming patch-level compatibility.

## Conclusion

Adopt NSQ when you want a message queue that installs as a handful of static binaries, runs without ZooKeeper or Erlang, and tolerates a node going down without a coordinator. Do not adopt it when you need ordered, replayable partitions with long retention, or when you want a managed queue with no operational surface at all. Before committing, verify three things: that your client library exposes the protocol features you need, that a consumer can survive a redelivery burst after a timeout, and that your disk sizing accounts for the mem-queue-size threshold where nsqd starts writing to /data. The last one is the difference between a queue that survives a restart and one that quietly drops what it held in RAM.

## FAQ

### What is NSQ used for?

NSQ is a realtime distributed messaging platform for moving messages between services. The README describes it as designed to operate at scale, handling billions of messages per day, with distributed and decentralized topologies that avoid single points of failure.

### How do I install NSQ?

The README points to binary releases for Linux, Darwin, FreeBSD and Windows, and to an official Docker image. The Dockerfile builds the binaries with CGO disabled and places them in /usr/local/bin inside the image.

### Does NSQ guarantee exactly-once delivery?

No. The README describes a reliable message delivery guarantee, and NSQ's model is at-least-once, so a consumer that fails before acknowledging will receive the message again. Consumers need to handle duplicates.

### What is the difference between NSQ and Kafka?

Kafka stores messages in a partitioned, replicated log that supports replaying history, while NSQ delivers messages through topics and channels without that log model. NSQ's disk-backed queue exists to survive restarts rather than to serve historical reads.

### Which ports does NSQ use?

The Dockerfile exposes 4150 and 4151 for nsqd, 4160 and 4161 for nsqlookupd, and 4170 and 4171 for nsqadmin. In each pair the higher port is the HTTP interface.

## Sources

- [License: MIT](https://github.com/nsqio/nsq/blob/master/LICENSE)
- [nsqio/nsq on GitHub](https://github.com/nsqio/nsq)
- [Project website](https://nsq.io)
- [README](https://github.com/nsqio/nsq/blob/master/README.md)
- [Releases](https://github.com/nsqio/nsq/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/nsqio-nsq
