nats.go: the Go client for NATS, from first publish to JetStream
Golang client for NATS, the cloud native messaging system.
At a glance
- What is it?
- nats.go is the official Go client for the NATS messaging system, covering core publish and subscribe, JetStream persistence, the beta service API and Nkeys authentication. It suits Go services that need a small dependency footprint and a broker they can run themselves.
- Who is it for?
- Adopt nats.go if your services are written in Go and you want a client whose only direct dependencies are a compression library, nkeys and nuid, with JetStream persistence reachable through the same connection. Do not adopt it if your team is not on Go, or if you need a message broker that stores and replays by default rather than one where persistence is a separate API you opt into.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What nats.go actually is, and who it is for
This is a client library, not a broker. The repository is the Go binding for NATS, the cloud native messaging system, and the README opens by describing it exactly that way. Everything the library does is done over a connection to a NATS server that you run, deploy or subscribe to separately.
The audience is narrow and specific: Go developers who need publish and subscribe, request and reply, or persistent streaming between services. The module declares go 1.26.0, so the toolchain expectation is current Go, not an older release line. The topics listed on the repository (cloud-native, microservices, pub-sub) describe the deployment style the project is aimed at, and the examples directory carries the same shape: nats-pub, nats-sub, nats-req, nats-rply, nats-qsub, nats-echo and nats-bench.
What it is not is equally clear from the layout. There is no server code here, no storage engine, no dashboard. If you want a message broker with a UI and a schema registry, this repository gives you the client half only.
How the client is put together: one connection, several APIs
The architecture visible in the repository is layered. At the bottom is a connection created by nats.Connect, which returns a connection handle used for core NATS operations: Publish, Subscribe, SubscribeSync, ChanSubscribe, Request and Drain. The README shows each of these in a single basic usage block, which is a fair summary of the surface area.
Above that sits JetStream, described in the README as the built-in NATS persistence system. It is reached through a separate import path, github.com/nats-io/nats.go/jetstream, and a separate constructor, jetstream.New(nc), which takes an existing core connection. From there the flow is stream handle, then consumer handle, then Consume with a callback that must call msg.Ack().
Two details in that flow matter. First, the JetStream context creation takes a context.Context with a timeout in the README example, so stream and consumer lookups are cancellable operations rather than instant local calls. Second, the README states that the current JetStream API replaces the legacy JetStream API, which is documented in a separate file, legacy_jetstream.md. Code written against the old API will still compile only if you keep using that older surface; the two are not the same thing.
The micro package holds the service API, which the README describes as currently in beta release. Treat that as a real status marker, not boilerplate.
Installing nats.go and publishing a first message
Installation is a single go get against the module path. The README gives the latest released client, a pinned version, and a note that the latest major version for the NATS server is v2.
go get github.com/nats-io/nats.go@latest
go get github.com/nats-io/[email protected]
go get github.com/nats-io/nats-server/v2@latestThe first two lines pull the client, either at the newest release or pinned to v1.54.0. The third line is the server, which you need running somewhere before any of the following code does anything useful.
A first real use is the subscribe-then-publish pair from the README. Note that the subscriber is registered before the publish call, and that nats.DefaultURL is used rather than a literal address.
import "github.com/nats-io/nats.go"
nc, _ := nats.Connect(nats.DefaultURL)
nc.Subscribe("foo", func(m *nats.Msg) {
fmt.Printf("Received a message: %s\n", string(m.Data))
})
nc.Publish("foo", []byte("Hello World"))The callback fires with the message bytes; printing them should show Hello World. The README ignores the error from Connect in this snippet, which is fine for a first run and wrong for production. The same block also shows the two shutdown paths: nc.Drain() is described as preferred for responders, and the README notes that Close() is not needed if Drain is called.
For persistence rather than fire-and-forget, the JetStream example in the README retrieves an existing stream and consumer, then consumes in a callback:
nc, _ := nats.Connect(nats.DefaultURL)
js, _ := jetstream.New(nc)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
stream, _ := js.Stream(ctx, "foo")
cons, _ := stream.Consumer(ctx, "cons")
cc, _ := cons.Consume(func(msg jetstream.Msg) {
fmt.Println("Received jetstream message: ", string(msg.Data()))
msg.Ack()
})
defer cc.Stop()This snippet assumes the stream named foo and the consumer named cons already exist. The README does not show their creation here, so you will need the jetstream/README.md for the management side.
Authentication, TLS and the memory handling claim
The credentials story is the part of the README with the most detail, and it is worth reading closely. The helper nats.UserCredentials takes either a single creds file path or a JWT path plus an NKey seed path. The README states that the helper creates two callback handlers, one to present the user JWT and one to sign the nonce challenge from the server, and that the core client library never has direct access to your private key.
The README also states that the helper will load and wipe and erase memory it uses for each connect or reconnect. That is a specific claim about a specific code path. It applies to the helper, not to every option. If you go low level with nats.Nkey(pubNkey, sigCB) and supply your own signature callback, you are managing the seed material yourself and the wipe guarantee does not follow you there.
TLS has three documented entry points. A tls:// scheme enables secure connections and verifies the server name. nats.RootCAs handles self-signed certificates by pointing at a CA file. nats.ClientCert supplies a client certificate and key when the server requires one. A full tls.Config can be passed through nats.Secure instead, and the README's example sets MinVersion to tls.VersionTLS12 explicitly rather than leaving it to the default.
One caveat sits at the top of that section: the README states this authentication mechanism requires a server with version 2.0.0 or higher. Older servers will not accept it.
Where nats.go is the wrong choice
Core NATS is fire-and-forget. A Publish call returns without any guarantee that a subscriber was connected. The README's own basic usage block makes this plain: the subscriber is registered and the publisher sends, but nothing in that path acknowledges delivery. If your requirement is durability by default, you are choosing the wrong layer unless you move to JetStream, and JetStream is a separate API with its own stream and consumer management that the README only gestures at.
There is a second, sharper limitation in the repository itself. The service API in the micro package is described by the README as being in beta release. Building production service discovery and request handling on a surface the project labels beta is a decision you should make deliberately.
The third limit is language. This is a Go client. The nats.go module path, the go 1.26.0 directive and the dependency list all confirm it. A polyglot team will end up with a different client per language, and the behaviour you rely on here does not transfer with your code.
Finally, the version split is a real hazard. The README states that the current JetStream API replaces the legacy one. If your existing code uses the legacy surface documented in legacy_jetstream.md, a migration is not optional forever, and the two APIs do not share a calling convention.
How nats.go compares with a Kafka client for Go
The honest comparison is not client against client, it is broker model against broker model, and the search questions people ask about this project reflect that. A Kafka client in Go connects to a log where topics are partitioned and retention is the default behaviour; consumers track offsets and replay from a position. NATS starts from a lightweight publish and subscribe server, and persistence is an add-on you reach through the JetStream API with explicit streams, consumers and acknowledgements.
The practical difference shows up in the code. A Kafka consumer is defined by a group and a partition assignment. The JetStream consumer in the README is retrieved by name from a stream and consumed through a callback that acknowledges each message individually. The mental model is different: one is a log you read, the other is a subscription you acknowledge.
There is also a dependency difference worth noting. The go.mod for nats.go lists three direct requirements: github.com/klauspost/compress, github.com/nats-io/nkeys and github.com/nats-io/nuid, with golang.org/x/crypto and golang.org/x/sys as indirect. That is a small graph, and it is a deliberate contrast with clients that pull in a large transitive tree. If your constraint is a lean build, that matters more than any feature comparison.
Neither choice is universal. If your organisation already runs Kafka and your teams know it, the operational argument usually wins. If you want a broker that is small to run and a client that is small to depend on, the NATS model is the one being offered here.
Maintenance, releases and what the Apache-2.0 licence means for you
The repository is not archived, and the last push was on 2026-09-18, the same day as the v1.54.0 release. The two releases before it, v1.53.0 and v1.53.1, both landed on 2026-08-11. That is the release cadence the repository supports, and it is the only basis for judging how alive the project is.
Upgrade cost is mostly a version-pinning question. The README shows both go get github.com/nats-io/nats.go@latest and a pinned go get github.com/nats-io/[email protected], so you can choose your exposure. The go.mod declares go 1.26.0, which means a toolchain upgrade may be a prerequisite for a client upgrade, and that is a cost that lands on your build images rather than on the library.
Testing has its own workflow. The Makefile notes that the default path needs no docker because a TestMain runs the ntf tester inside each test binary, and it offers make test T=TestName PKG=./test/... for a single test. There is also a server-replace target that points the in-process tester at another nats-server through a replace directive in go_test.mod, with an explicit warning never to commit the directive and a note to prefer it over go get. If you contribute upstream, that is the workflow you will meet.
On licensing, the project is Apache-2.0, and the README carries the standard Apache 2 badge. That is a permissive licence with a patent grant and attribution requirements. It is not legal advice, and if you redistribute the library in a product you should have your own counsel read the terms.
Editorial conclusion
Adopt nats.go if your services are written in Go and you want a client whose only direct dependencies are a compression library, nkeys and nuid, with JetStream persistence reachable through the same connection. Do not adopt it if your team is not on Go, or if you need a message broker that stores and replays by default rather than one where persistence is a separate API you opt into. Before committing, verify the NATS server version you will run against, because the README states the Nkeys and user credentials mechanism requires a server at 2.0.0 or later, and confirm which JetStream API you are writing against, since the current one replaces the legacy API documented in legacy_jetstream.md.
Frequently asked questions
Is NATS better than Kafka?
The two are different broker models rather than interchangeable clients. A Kafka consumer is defined by a group and a partition assignment against a partitioned log, while JetStream in nats.go retrieves a named consumer from a stream and acknowledges each message individually through a callback. The nats.go go.mod also lists only three direct dependencies, which matters if a lean build is your constraint.
What is NATS used for?
The README describes nats.go as a Go client for the NATS messaging system, with core publish and subscribe, request and reply, and the JetStream persistence system for managing assets and consuming persistent messages. The repository topics list cloud-native, microservices and pub-sub as the intended use.
Is NATS deprecated?
The nats.go repository is not archived, and the last push was on 2026-09-18, the same day as the v1.54.0 release. One part of the client is marked for replacement: the README states that the current JetStream API replaces the legacy JetStream API documented in legacy_jetstream.md.
Is NATS free to use?
The nats.go repository is licensed under Apache-2.0, as shown in the README badge and the LICENSE file. That covers the client library; the README does not describe terms for any hosted service.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nats-io-nats-go)