NATS Server — API Surface#

API types#

NATS Server exposes functionality through five distinct surfaces:

  1. NATS Wire Protocol — the primary, native TCP protocol (text-based)
  2. JetStream Subject API — pub/sub-based control plane over $JS.API.* subjects
  3. HTTP Monitoring API — read-only observability endpoints on a separate port
  4. CLInats-server binary with stdlib flag-based flags
  5. Embedded Library API — the server package is publicly exported for in-process embedding

Additionally, two protocol bridges are served on top of the core:

  • MQTT 3.1.1 bridge — clients speaking MQTT are mapped to NATS accounts/subjects
  • WebSocket bridge — standard NATS protocol tunneled over WebSocket

There is no gRPC API and no REST control plane (monitoring is read-only).


NATS Wire Protocol (primary API)#

  • Transport: Raw TCP (or TLS). Optionally WebSocket upgrade.
  • Format: Line-oriented text protocol. Each operation is a keyword followed by optional args, then \r\n, then optional payload.
  • Connection: Clients connect to port 4222 by default, receive INFO {...} JSON blob, then send CONNECT {...}.
  • Core operations:
Client → ServerDescription
CONNECT {opts}Authenticate and negotiate protocol version
PUB <subject> [reply] <#bytes>\r\n<payload>Publish a message
HPUB <subject> [reply] <#hdr bytes> <#total bytes>\r\n<headers>\r\n<payload>Publish with headers (NATS v2.2+)
SUB <subject> [queue] <sid>Subscribe to a subject
UNSUB <sid> [max_msgs]Unsubscribe
PINGKeepalive ping
PONGKeepalive pong
Server → ClientDescription
INFO {json}Server info on connect (also sent on topology changes)
MSG <subject> <sid> [reply] <#bytes>\r\n<payload>Deliver a message
HMSG <subject> <sid> [reply] <#hdr bytes> <#total bytes>\r\n<headers>\r\n<payload>Deliver with headers
PINGServer-initiated keepalive
+OKAcknowledgment (verbose mode only)
-ERR <msg>Error response
  • Route protocol (cluster peers): same connection type (client) but kind=ROUTER. Adds route-specific extensions (RS — route subscribe, RM — route message, etc.).
  • Gateway protocol (super-cluster): kind=GATEWAY. Uses CONNECT with gateway token + account-aware message forwarding.
  • Leaf node protocol: kind=LEAF. JWT-based auth, selective subject import/export.
  • Protocol parsing: server/parser.go — a hand-written zero-allocation state machine, no external parser library.

JetStream Subject API#

The JetStream control and data plane is exposed entirely through NATS subjects. Clients send request-reply messages to $JS.API.* subjects; the server’s internal subscriptions route these to handler functions in server/jetstream_api.go.

All subjects live under $JS.API.* (or $JS.<domain>.API.* in multi-tenant domain configurations). Subject constants are defined as exported const values in server/jetstream_api.go, making them part of the public API.

Account-level#

SubjectDescription
$JS.API.INFOJetStream account info and limits
$JS.API.ACCOUNT.PURGE.<account>Purge all JetStream data for an account

Stream management#

SubjectDescription
$JS.API.STREAM.CREATE.<name>Create a stream
$JS.API.STREAM.UPDATE.<name>Update a stream’s configuration
$JS.API.STREAM.INFO.<name>Get stream info
$JS.API.STREAM.NAMESList stream names
$JS.API.STREAM.LISTList streams with full detail
$JS.API.STREAM.DELETE.<name>Delete a stream
$JS.API.STREAM.PURGE.<name>Purge messages from a stream
$JS.API.STREAM.SNAPSHOT.<name>Initiate a stream snapshot
$JS.API.STREAM.RESTORE.<name>Restore a stream from snapshot
$JS.API.STREAM.MSG.GET.<name>Get a message by sequence number
$JS.API.STREAM.MSG.DELETE.<name>Delete a specific message by sequence
$JS.API.DIRECT.GET.<name>Direct (non-API) fast message get by seq
$JS.API.DIRECT.GET.<name>.>Direct fast get by last matching subject

Consumer management#

SubjectDescription
$JS.API.CONSUMER.CREATE.<stream>Create an ephemeral consumer
$JS.API.CONSUMER.CREATE.<stream>.<consumer>.<filter>Create consumer with filter
$JS.API.CONSUMER.DURABLE.CREATE.<stream>.<name>Create a durable consumer
$JS.API.CONSUMER.INFO.<stream>.<consumer>Get consumer info
$JS.API.CONSUMER.NAMES.<stream>List consumer names
$JS.API.CONSUMER.LIST.<stream>List consumers with full detail
$JS.API.CONSUMER.DELETE.<stream>.<consumer>Delete a consumer
$JS.API.CONSUMER.PAUSE.<stream>.<consumer>Pause or unpause a consumer
$JS.API.CONSUMER.UNPIN.<stream>.<consumer>Unpin pinned subscription
$JS.API.CONSUMER.RESET.<stream>.<consumer>Reset consumer to new starting sequence
$JS.API.CONSUMER.MSG.NEXT.<stream>.<consumer>Pull next message(s) from consumer
$JS.API.CONSUMER.LEADER.STEPDOWN.<stream>.<consumer>Consumer leader stepdown

Cluster administration (operator-level)#

SubjectDescription
$JS.API.META.LEADER.STEPDOWNStep down the JetStream meta-leader
$JS.API.SERVER.REMOVERemove a server from the JetStream meta group
$JS.API.STREAM.PEER.REMOVE.<stream>Remove a peer from a replicated stream
$JS.API.STREAM.LEADER.STEPDOWN.<stream>Step down a stream’s Raft leader

Advisory events (server → subscribers)#

NATS publishes advisory events on $JS.EVENT.ADVISORY.* subjects. These are fire-and-forget; subscribers observe cluster state changes:

Subject prefixEvent
$JS.EVENT.ADVISORY.STREAM.CREATEDStream created
$JS.EVENT.ADVISORY.STREAM.UPDATEDStream updated
$JS.EVENT.ADVISORY.STREAM.DELETEDStream deleted
$JS.EVENT.ADVISORY.CONSUMER.CREATEDConsumer created
$JS.EVENT.ADVISORY.CONSUMER.DELETEDConsumer deleted
$JS.EVENT.ADVISORY.CONSUMER.PAUSEConsumer paused/unpaused
$JS.EVENT.ADVISORY.CONSUMER.PINNED / UNPINNEDConsumer pin state
$JS.EVENT.ADVISORY.STREAM.LEADER_ELECTEDStream leader election
$JS.EVENT.ADVISORY.STREAM.QUORUM_LOSTStream lost quorum
$JS.EVENT.ADVISORY.DOMAIN.LEADER_ELECTEDMeta-leader election
$JS.EVENT.ADVISORY.SERVER.OUT_OF_STORAGEServer storage exhausted
$JS.EVENT.ADVISORY.SERVER.REMOVEDServer removed from cluster
$JS.EVENT.ADVISORY.API.LIMIT_REACHEDJetStream API rate limit
$JS.EVENT.ADVISORY.APIJetStream API audit log (every API call)

Design note: Exposing the entire JetStream API through NATS subjects rather than a separate REST or gRPC endpoint is an intentional architectural choice. It means JetStream API calls get TLS, account isolation, and authorization from the core NATS protocol automatically — no separate auth layer needed.


HTTP Monitoring API (read-only)#

NATS exposes an HTTP monitoring server on a separate port (default: 8222, configured via -m/-ms flags or http_port/https_port). All endpoints are read-only — there is no HTTP control plane. This is intentional: management is done through the JetStream subject API or CLI signals.

Route registration in server/server.go:3141-3171 using stdlib net/http ServeMux:

PathHandlerDescription
/HandleRootServer info summary
/varzHandleVarzServer metrics and configuration
/connzHandleConnzActive connection details (paginated, sortable)
/routezHandleRoutezCluster route connection details
/gatewayzHandleGatewayzSuper-cluster gateway details
/leafzHandleLeafzLeaf node connection details
/subszHandleSubszSubscription count and detail
/stackszHandleStackszGoroutine stacks (debug)
/accountzHandleAccountzAccount info
/accstatzHandleAccountStatzPer-account statistics
/jszHandleJszJetStream statistics
/healthzHandleHealthzHealth check (for load balancers)
/ipqueueszHandleIPQueueszInternal IP queue stats
/raftzHandleRaftzRaft group status
/debug/varsexpvar.Handler()Go expvar (standard process metrics)
  • Router: stdlib http.ServeMux (no third-party router)
  • Authentication: Optional HTTP basic auth or token auth (configurable in Options.HTTPBasicAuth, Options.HTTPUsername, Options.HTTPPassword)
  • Response format: JSON (all HandleXXX methods marshal Go structs to JSON)
  • CORS/TLS: Monitoring port can be TLS-protected (https_port); no CORS headers
  • External access: (s *Server) HTTPHandler() http.Handler allows embedding the monitoring handler into an external HTTP server

CLI#

  • Framework: stdlib flag.FlagSet (no Cobra, no urfave/cli)
  • Binary: nats-server — single binary, no subcommands
  • Command structure: All configuration is done via flags or a config file; there is no subcommand tree

Key flags#

FlagDescription
-a, --addrBind address (default 0.0.0.0)
-p, --portClient listen port (default 4222)
-c, --configConfiguration file path
-tTest configuration and exit
-m, --http_portMonitoring HTTP port
-ms, --https_portMonitoring HTTPS port
-js, --jetstreamEnable JetStream
-sd, --store_dirJetStream storage directory
--routesCluster peer URLs to solicit
--clusterCluster listen URL
--tls, --tlscert, --tlskey, --tlsverify, --tlscacertTLS options
--user, --pass, --authSimple authentication
-sl, --signalSend signal to running server (ldm, stop, quit, term, reopen, reload)
--profilepprof HTTP port
-D, -V, -DV, -VV, -DVVDebug/trace verbosity levels
  • Signal handling: The -sl flag sends OS signals to a running server. reload triggers SIGHUPserver.Reload(). ldm triggers lame-duck mode (graceful drain). stop/quit/term terminate the process.
  • Config file: Custom .conf format (HCL-like) parsed by conf/ package. Supports a superset of what flags expose: TLS, auth, clustering, JetStream, MQTT, leaf nodes, operator JWT chains, imports/exports, subject mappings, rate limits, etc.

Embedded Library API#

The server package is fully public and intended for in-process embedding (used extensively in the test suite and by projects like nats.go test helpers).

Constructor functions#

// Primary constructors
func NewServer(opts *Options) (*Server, error)
func NewServerFromConfig(opts *Options) (*Server, error)  // alias
func New(opts *Options) *Server                            // panic on error variant

// Options loading
func ConfigureOptions(fs *flag.FlagSet, args []string, ...) (*Options, error)
func ProcessConfigFile(configFile string) (*Options, error)
func MergeOptions(fileOpts, flagOpts *Options) *Options

Lifecycle methods (*Server)#

func (s *Server) Start()
func (s *Server) Shutdown()
func (s *Server) WaitForShutdown()
func (s *Server) Reload() error
func (s *Server) ReloadOptions(newOpts *Options) error
func (s *Server) LameDuckShutdown()
func (s *Server) ReadyForConnections(dur time.Duration) bool

Inspection methods (*Server)#

func (s *Server) ID() string
func (s *Server) Name() string
func (s *Server) ClusterName() string
func (s *Server) ClientURL() string
func (s *Server) WebsocketURL() string
func (s *Server) Addr() net.Addr
func (s *Server) MonitorAddr() *net.TCPAddr
func (s *Server) ClusterAddr() *net.TCPAddr
func (s *Server) Running() bool
func (s *Server) NumClients() int
func (s *Server) NumRoutes() int
func (s *Server) NumLeafNodes() int
func (s *Server) NumSubscriptions() uint32
func (s *Server) NumActiveAccounts() int32
func (s *Server) ActivePeers() []string
func (s *Server) HTTPHandler() http.Handler

Account management (*Server)#

func (s *Server) RegisterAccount(name string) (*Account, error)
func (s *Server) LookupOrRegisterAccount(name string) (*Account, bool)
func (s *Server) LookupAccount(name string) (*Account, error)
func (s *Server) SetSystemAccount(accName string) error
func (s *Server) SystemAccount() *Account
func (s *Server) GlobalAccount() *Account
func (s *Server) SetDefaultSystemAccount() error

JetStream (*Server)#

func (s *Server) EnableJetStream(config *JetStreamConfig) error

In-process connection#

func (s *Server) InProcessConn() (net.Conn, error)

Returns a net.Conn that bypasses TCP, allowing in-process clients to connect without network overhead. Used heavily in testing.

API style#

  • No functional options for server construction — configuration is through the Options struct (a flat struct with ~200 fields)
  • No builder patternOptions is set up directly by field assignment or loaded from config
  • Backward compatibility: No explicit versioning strategy visible in the Go API. The module path is github.com/nats-io/nats-server/v2, establishing a v2 module boundary. Breaking changes are managed through the module major version.

Protocol bridges#

MQTT 3.1.1#

  • Listen port: Configurable (mqtt.port in config, or Options.MQTT.Port)
  • Protocol: Full MQTT 3.1.1 client support (server/mqtt.go, ~6000 lines)
  • Mapping: MQTT topics → NATS subjects (slash-to-dot conversion). QoS 0 → fire-and-forget publish. QoS 1 → JetStream-backed delivery with ACK.
  • Session persistence: MQTT persistent sessions stored in JetStream streams
  • Auth: MQTT username/password mapped to NATS auth credentials

WebSocket#

  • Listen port: Configurable (websocket.port or Options.Websocket.Port)
  • Protocol: Standard NATS text protocol tunneled over WebSocket (server/websocket.go)
  • TLS: Independent TLS config from the main client port
  • Compression: Per-message deflate compression support
  • Limitation: Full NATS feature parity (headers, JetStream, etc.) — not a subset protocol

Summary of API surface characteristics#

DimensionDetail
Primary protocolNATS wire protocol (custom text, TCP)
Management APINATS subjects ($JS.API.*) — no separate REST control plane
ObservabilityHTTP (read-only, stdlib mux)
CLIstdlib flag (no subcommands, signal-based control)
Libraryserver package exported for embedding
BridgesMQTT 3.1.1, WebSocket
gRPCNone
Plugin systemNone — extensions via account imports/exports

The most architecturally notable aspect of NATS’s API surface is that the management and data planes are unified through the same NATS protocol. There is no secondary HTTP REST API for JetStream control — operators and clients both speak NATS subjects. This means the auth, TLS, and account isolation of the core protocol automatically applies to the management API, eliminating an entire class of API design problems at the cost of requiring a NATS client (rather than curl) to administer JetStream.