NATS Server Documentation

repository·main·Indexed Apr 15, 2026

https://github.com/nats-io/nats-server

Official documentation for nats-server, a high-performance, secure messaging system for distributed systems and part of the CNCF. Supports MQTT v3.1.1, JetStream persistence, and over 40 client languages. Includes details on stream imports, shadow subscriptions, subscription limits, client disconnection cleanup, and JetStream consumer management with priority policies and delivery options.

Tokens
138.6K
Snippets
289
Records
493
Agent score
98%

What's inside nats-server

  1. Query Server Statistics and State

    main

    Access the following methods to retrieve real-time statistics about the server's connections and performance:

    • NumClients(): Returns the number of registered clients.
    • NumRoutes(): Returns the number of registered routes.
    • NumRemotes(): Returns the number of registered remotes.
    • NumLeafNodes(): Returns the number of leaf node connections.
    • NumSubscriptions(): Returns the total number of active subscriptions.
    • NumSlowConsumers(): Returns the total count of slow consumers.
    • NumStalledClients(): Returns the total number of times clients have been stalled.
    • NumStaleConnections(): Returns the number of stale connections.

    For granular breakdowns, use the specific stats methods:

    • NumSlowConsumersClients(), NumSlowConsumersRoutes(), NumSlowConsumersGateways(), NumSlowConsumersLeafs()
    • NumStaleConnectionsClients(), NumStaleConnectionsRoutes(), NumStaleConnectionsGateways(), NumStaleConnectionsLeafs()

    Sources: server/server.go

  2. NATS Server Overview

    main
    NATS is a simple, secure, and performant communications system for digital systems, services, and devices. It is part of the Cloud Native Computing Foundation (CNCF) and supports over 40 client language implementations. The server can run on-premise, in the cloud, at the edge, or on devices like a Raspberry Pi.
  3. Calculate Pending Messages for Consumers

    main

    The consumer calculates the number of pending messages (numPending) based on the stream state and delivery policy. This is used to inform clients about how many messages are available for delivery.

    Calculation Logic:

    • The consumer checks the stream's LastSeq and compares it to the consumer's sseq (stream sequence).
    • If sseq exceeds LastSeq, the pending count is reset to 0.
    • For filtered consumers, the calculation uses NumPendingMulti with subject filters.
    • For DeliverLastPerSubject policy, the calculation is adjusted to reflect the last message per subject.

    Methods:

    • streamNumPendingLocked(): Acquires the consumer lock and calls streamNumPending().
    • streamNumPending(): Calculates the pending count based on delivery policy and filters.
    • calculateNumPending(): Performs the actual calculation using the stream store.
    • checkNumPending(): Validates the pending count against the stream state to prevent reporting more messages than exist.

    Example Usage:

    // Get the number of pending messages
    pending, err := consumer.StreamNumPendingLocked()
    if err != nil {
        // Handle error
    }

    Important Notes:

    • The checkNumPending() method includes sanity checks to handle race conditions during stream deletion or message removal.
    • If the consumer is not filtered, the calculation uses the stream's NumPending method with an empty filter.
    • For filtered consumers, the calculation uses NumPendingMulti with the configured subject filters.
    // Example: Calculate pending messages
    func (o *consumer) streamNumPending() (uint64, error) {
        if o.mset == nil || o.mset.store == nil {
            o.npc, o.npf = 0, 0
            return 0, nil
        }
        npc, npf, err := o.calculateNumPending()
        if err != nil {
            return 0, err
        }
        o.npc, o.npf = int64(npc), npf
        return o.numPending(), nil
    }
    
    // Example: Check pending count sanity
    func (o *consumer) checkNumPending() (uint64, error) {
        if o.mset != nil && o.mset.store != nil {
            var state StreamState
            o.mset.store.FastState(&state)
            npc := o.numPending()
            if o.sseq > state.LastSeq {
                o.npc = 0
            } else if npc > 0 {
                o.npc = int64(min(npc, state.Msgs, state.LastSeq-o.sseq+1))
            }
        }
        return o.numPending(), nil
    }

    Sources: server/consumer.go

  4. MQTT Implementation Overview

    main
    The NATS Server implements the MQTT v3.1.1 specification. This guide outlines the core concepts, lifecycles, and how the server utilizes JetStream to manage MQTT sessions, messages, and subscriptions.
  5. Check Server Header Support

    main

    Use supportsHeaders to determine if the server is configured to support NATS message headers. This returns false if the NoHeaderSupport option is enabled or if the server instance is nil.

    Usage:

    if server.supportsHeaders() {
        // Safe to use headers in messages
    } else {
        // Headers are disabled
    }

    Returns:

    • bool: true if headers are supported, false otherwise.

    Sources: server/server.go

  6. Usage

    main
    1. Create stream in source account:
    _, err := js.AddStream(&nats.StreamConfig{
        Name: "ORDERS",
        Subjects: []string{"foo"},
        Storage: nats.MemoryStorage,
    })
    1. Create consumer with delivery subject:
    _, err = js.AddConsumer("ORDERS", &nats.ConsumerConfig{
        DeliverSubject: "deliver.ORDERS",
        AckPolicy: nats.AckExplicitPolicy,
    })
    1. Subscribe in importing account with remapped subject:
    // Messages published to "foo" arrive as "bar.ORDERS" in importing account
    sub, err := nc2.SubscribeSync("bar.ORDERS")

    The to field in the import configuration remaps the subject from the source account to the importing account's namespace.

    imports [
        { stream: { account: JS, subject: "deliver.ORDERS" }, to: "d.*" }
        { stream: { account: JS, subject: "foo.*" }, to: "bar.*" }
    ]
    
    // Consumer receives messages with remapped subject
    sub, err := nc2.SubscribeSync("bar.ORDERS")

    Sources: server/jetstream_test.go

  7. Usage

    main
    var resp JSApiAccountPurgeResponse
    ncsys := natsConnect(t, s.ClientURL(), nats.UserCredentials(sysCreds))
    defer ncsys.Close()
    
    m, err := ncsys.Request(fmt.Sprintf(JSApiAccountPurgeT, accpub), nil, 5*time.Second)
    require_NoError(t, err)
    
    err = json.Unmarshal(m.Data, &resp)
    require_NoError(t, err)
    require_True(t, resp.Initiated)
  8. Usage

    main

    When publishing messages, set the JSMsgId header:

    m := nats.NewMsg("foo.1")
    m.Header.Add(nats.JSMsgId, "unique-id-1")
    m.Data = []byte("Hello DeDupe!")
    resp, _ := nc.RequestMsg(m, 100*time.Millisecond)

    If a message with the same ID is sent within the Duplicates window, the server returns a PubAck with Duplicate: true and does not store the message again.

  9. Get Client Account and RTT

    main

    Access the account associated with a client and retrieve its Round-Trip Time (RTT) value safely using locks.

    Functions:

    • Account() *Account: Returns the account associated with the client. Returns nil if the client is nil.
    • getRTTValue() time.Duration: Returns the current RTT value. Protects access with the client lock.

    Usage: These are safe, public methods to inspect client state without needing to manage locks directly.

    Sources: server/client.go

  10. Setup WorkQueue Source

    main
    // Create source stream
    _, err := js.AddStream(&nats.StreamConfig{
        Name: "FOO",
        Subjects: []string{"foo"},
    })
    
    // Create workqueue stream with source
    _, err = js.AddStream(&nats.StreamConfig{
        Name: "TEST",
        Retention: nats.WorkQueuePolicy,
        Sources: []*nats.StreamSource{{Name: "FOO"}},
    })
    
    // Add consumer
    _, err = js.AddConsumer("TEST", &nats.ConsumerConfig{
        Durable: "dur",
        AckPolicy: nats.AckExplicitPolicy,
    })