NATS Server — Structure#
Layout pattern#
Custom / Dominant-Package Flat
NATS Server does not use the standard Go cmd/internal/pkg layout. There is a single main.go at the repository root, and almost all server logic lives in one large server/ package (~180 non-test .go files, ~130K lines of source). Sub-packages within server/ are pure algorithmic data structures, not domain decompositions. This is a deliberate, performance-driven choice: keeping everything in one package eliminates cross-package interface overhead and simplifies the call graph for a hot-path network server.
Directory map#
nats-server/
├── main.go # Single binary entry point; thin wrapper around server package
├── conf/ # NATS config file parser (lexer + parser, standalone package)
│ ├── lex.go # Lexer for .conf files
│ ├── parse.go # Parser producing config trees
│ └── includes/ # Sample include files for testing
├── doc/ # Protocol and design documentation
├── docker/ # Dockerfile.nightly + sample nats-server.conf
├── internal/ # Hidden implementation packages (not for external use)
│ ├── antithesis/ # Antithesis fuzzing/fault-injection SDK integration
│ ├── fastrand/ # Fast non-crypto PRNG (avoids global mutex of math/rand)
│ ├── ldap/ # LDAP DN parsing for auth
│ ├── ocsp/ # OCSP response caching / stapling logic
│ └── testhelper/ # Shared helpers for internal test code
├── logger/ # Logging package (file, syslog, Windows event log)
│ ├── log.go # Logger interface + file-based implementation
│ └── syslog*.go # Syslog and Windows event log backends
├── logos/ # Project branding assets
├── scripts/ # Shell scripts: coverage, CI helpers, copyright updater
├── server/ # Core server (dominant package; ~180 source files)
│ ├── server.go # Server struct, lifecycle (Start/Shutdown/Run)
│ ├── client.go # Client connection state machine (~6800 lines)
│ ├── opts.go # Options/config struct (~6500 lines)
│ ├── accounts.go # Multi-tenancy account model (~4800 lines)
│ ├── auth.go # Authentication / authorization
│ ├── parser.go # NATS wire protocol parser
│ ├── sublist.go # Subject subscription routing (trie-based)
│ ├── route.go # Cluster routing between server nodes
│ ├── gateway.go # Super-cluster gateway protocol (~3400 lines)
│ ├── leafnode.go # Leaf node protocol for edge/hub (~3500 lines)
│ ├── jetstream.go # JetStream initialization and coordination
│ ├── jetstream_api.go # JetStream management API handler (~5300 lines)
│ ├── jetstream_cluster.go # Raft-backed JetStream cluster (~10900 lines)
│ ├── stream.go # JetStream stream state machine (~8700 lines)
│ ├── consumer.go # JetStream consumer state machine (~6900 lines)
│ ├── filestore.go # JetStream file-backed message store (~13400 lines)
│ ├── memstore.go # JetStream in-memory message store
│ ├── store.go # Store interfaces (MsgStore, StreamStore)
│ ├── raft.go # Custom Raft consensus implementation (~5100 lines)
│ ├── mqtt.go # MQTT 3.1.1 protocol bridge (~6000 lines)
│ ├── websocket.go # WebSocket protocol upgrade
│ ├── monitor.go # HTTP monitoring/stats endpoint (~4300 lines)
│ ├── reload.go # Hot config reload logic
│ ├── events.go # System account events and advisories
│ ├── errors.go # Error types and sentinel errors
│ ├── errors_gen.go # Generated error constants (from errors.json)
│ ├── jwt.go # JWT-based decentralized auth
│ ├── nkey.go # NKey (NaCl keypair) auth handling
│ ├── ocsp.go # OCSP stapling integration
│ ├── msgtrace.go # Message tracing / distributed tracing
│ ├── service.go # Micro-services (request/reply service wrapper)
│ ├── scheduler.go # Cron-style job scheduler (for JetStream)
│ ├── sendq.go # Async send queue for outbound messages
│ ├── ipqueue.go # Lock-free inbound packet queue
│ ├── ring.go # Ring buffer for closed-connection tracking
│ ├── signal.go # OS signal handling (SIGHUP reload, etc.)
│ ├── proto.go # Protocol constants
│ ├── const.go # Server-wide constants
│ ├── cron.go # Cron expression parser
│ ├── dirstore.go # JWT directory-based credential store
│ ├── subject_transform.go # Subject mapping and transformation rules
│ ├── util.go # Internal utility functions
│ ├── log.go # Server-side logger adapter
│ ├── ats/ # Adaptive Token Sampler — sequence set for AckSampling
│ ├── avl/ # AVL tree — used for ordered sequence tracking
│ ├── certidp/ # Certificate identity provider (OCSP + X.509 DN)
│ ├── certstore/ # Windows certificate store access
│ ├── elastic/ # Elastic scaling helper (grow-only slice variant)
│ ├── gsl/ # Generic Sorted List — fast ordered collection
│ ├── pse/ # Platform-specific process stats (CPU, memory) — 12 OS files
│ ├── stree/ # Subject-trie: ART (Adaptive Radix Tree) for subject routing
│ ├── sysmem/ # System memory queries — 7 OS-specific files
│ ├── thw/ # Token Hash Wheel — timing-wheel for per-subscriber rate limiting
│ └── tpm/ # TPM 2.0 support for hardware-bound JetStream encryption keys
├── test/ # External integration test suite (separate package)
│ └── configs/ # Config files used by integration tests
└── util/ # Standalone utility package (string/number helpers)Entry points#
| File | Binary | Purpose |
|---|---|---|
main.go | nats-server | Single binary entry point. Parses CLI flags via stdlib flag, calls server.ConfigureOptions, creates a server.Server, configures the logger, and blocks on server.Run + s.WaitForShutdown. All real logic delegates immediately to the server package. |
There is no cmd/ subdirectory. The root main.go is the only binary produced.
Package organization#
Internal packages (
internal/):internal/antithesis— Fault-injection integration for the Antithesis testing platforminternal/fastrand— Fast non-cryptographic PRNG, avoidsmath/randglobal lockinternal/ldap— LDAP distinguished name parser for user-attribute authinternal/ocsp— OCSP response cache (stapling, peer verification)internal/testhelper— Shared test utilities for internal packages
Public sub-packages under
server/: (importable, but only meaningfully used by the server itself)server/ats— Adaptive Token Sampler (sequence set used for JetStream ACK sampling)server/avl— AVL balanced binary tree (ordered sequence/offset tracking)server/certidp— Certificate-based identity provider via OCSP and X.509server/certstore— Windows certificate store integrationserver/elastic— Elastic/growable slice abstraction for internal poolingserver/gsl— Generic Sorted List for fast in-order operationsserver/pse— Process stats exporter: per-OS CPU/memory readings (12 build-tag files)server/stree— Subject-trie using Adaptive Radix Tree (ART) nodes for subject matchingserver/sysmem— System-level memory availability queries (7 OS-specific files)server/thw— Token Hash Wheel for per-connection rate limitingserver/tpm— TPM 2.0 hardware key management for JetStream encryption
Other packages:
conf/— Standalone configuration file parser; used byserver/opts.goto load.conffileslogger/— Logger abstraction with file, syslog, and Windows event log backends; used byserver/log.goutil/— Miscellaneous string/numeric helpers; thin and rarely used
Layering: The architecture is effectively two-layer:
server(everything) → thin support packages (conf,logger,internal/*,server/*). There is no hexagonal, clean, or onion layering. The dominantserverpackage owns all domain logic, wire protocols, storage, clustering, and security policy.
Build system#
- Build tool: No Makefile found. Build is driven by
go build,go test, and GitHub Actions. - Key targets:
go build .→ producesnats-serverbinarygo generate ./server/→ regenerateserrors_gen.gofromerrors.jsonviaserver/errors_gen.go
- CI: GitHub Actions workflows in
.github/workflows/:tests.yaml(main),long-tests.yaml,mqtt-test.yaml,nightly.yaml,release.yaml,vuln.yaml,cov.yaml - Docker: Single
docker/Dockerfile.nightly— appears to be a nightly scratch-based build; no multi-stage production Dockerfile in the tree
Notable structural decisions#
One package to rule them all. The
serverpackage (~180.gofiles) is the entire server. This is a deliberate performance trade-off: no interface indirection across package boundaries on hot paths (e.g., client message dispatch), no import cycles to manage, and simpler test setup. The cost is reduced modularity and a package that is very large by conventional Go standards.Sub-packages as algorithm libraries, not domain slices. The
server/stree,server/avl,server/gsl,server/thw, andserver/atspackages are all pure data structure/algorithm implementations, not feature slices. This keeps the domain logic consolidated while still allowing data structure reuse and independent testing.Aggressive OS portability through build tags. The
server/pse(process stats) andserver/sysmem(memory queries) packages each contain a separate.gofile per operating system: Linux, Darwin, FreeBSD, NetBSD, OpenBSD, Solaris, Windows, WASM, z/OS. This is not abstracted through an interface — it’s pure OS-conditional compilation, keeping zero overhead on the supported platform.External integration tests in a separate
test/package. Unit and component tests live alongside source inserver/*_test.go. A second, top-leveltest/directory holds black-box integration tests that import theserverpackage externally — a clean separation of white-box and black-box testing without needing acmd/structure.Generated code for error taxonomy.
server/errors.jsonis the source of truth for JetStream API error codes;server/errors_gen.gogenerates both Go constants and documentation from it viago generate. This makes the error surface machine-readable and consistent across client SDKs.Security primitives isolated in
internal/. OCSP, LDAP DN parsing, and TPM integration are ininternal/or inserver/certidp,server/certstore,server/tpm— kept separate from the main server logic to allow focused auditing. The Trail of Bits security audit referenced in governance docs likely benefited from this separation.