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#

FileBinaryPurpose
main.gonats-serverSingle 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 platform
    • internal/fastrand — Fast non-cryptographic PRNG, avoids math/rand global lock
    • internal/ldap — LDAP distinguished name parser for user-attribute auth
    • internal/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.509
    • server/certstore — Windows certificate store integration
    • server/elastic — Elastic/growable slice abstraction for internal pooling
    • server/gsl — Generic Sorted List for fast in-order operations
    • server/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 matching
    • server/sysmem — System-level memory availability queries (7 OS-specific files)
    • server/thw — Token Hash Wheel for per-connection rate limiting
    • server/tpm — TPM 2.0 hardware key management for JetStream encryption
  • Other packages:

    • conf/ — Standalone configuration file parser; used by server/opts.go to load .conf files
    • logger/ — Logger abstraction with file, syslog, and Windows event log backends; used by server/log.go
    • util/ — 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 dominant server package 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 . → produces nats-server binary
    • go generate ./server/ → regenerates errors_gen.go from errors.json via server/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#

  1. One package to rule them all. The server package (~180 .go files) 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.

  2. Sub-packages as algorithm libraries, not domain slices. The server/stree, server/avl, server/gsl, server/thw, and server/ats packages 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.

  3. Aggressive OS portability through build tags. The server/pse (process stats) and server/sysmem (memory queries) packages each contain a separate .go file 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.

  4. External integration tests in a separate test/ package. Unit and component tests live alongside source in server/*_test.go. A second, top-level test/ directory holds black-box integration tests that import the server package externally — a clean separation of white-box and black-box testing without needing a cmd/ structure.

  5. Generated code for error taxonomy. server/errors.json is the source of truth for JetStream API error codes; server/errors_gen.go generates both Go constants and documentation from it via go generate. This makes the error surface machine-readable and consistent across client SDKs.

  6. Security primitives isolated in internal/. OCSP, LDAP DN parsing, and TPM integration are in internal/ or in server/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.