$npx -y skills add kaustavdm/nats-skill --skill natsUse when developing with NATS messaging, deploying or embedding a NATS server, working with JetStream streams/consumers/KV/object-store, configuring NATS security or clustering, or building microservices on the NATS protocol
| 1 | # NATS Development Reference |
| 2 | |
| 3 | > Docs: https://docs.nats.io | Examples: https://natsbyexample.com |
| 4 | |
| 5 | NATS is a subject-based connective layer for distributed systems. Messages route by **subject string**, not hostname:port. Server binary is ~20MB, runs on Raspberry Pi to cloud. CNCF project, Apache 2.0 licensed, 40+ client libraries. Max message payload: 1MB default (configurable up to 64MB; keep under ~8MB in practice). |
| 6 | |
| 7 | Two planes — choose before designing: |
| 8 | |
| 9 | | Plane | Delivery | Persistence | Use for | |
| 10 | |-------|----------|-------------|---------| |
| 11 | | **Core NATS** | At-most-once | None | Fire-and-forget, RPC, real-time fan-out | |
| 12 | | **JetStream** | At-least/exactly-once | Streams | Durable queues, replay, KV state, work queues | |
| 13 | |
| 14 | Deep reference files in `references/`: |
| 15 | - [`jetstream.md`](references/jetstream.md) — full StreamConfig/ConsumerConfig fields, async publish, KV/object-store ops |
| 16 | - [`server-deployment.md`](references/server-deployment.md) — full config options, Docker, Kubernetes, Go embedding struct |
| 17 | - [`security.md`](references/security.md) — NKey, JWT/operator model, nsc CLI, TLS, auth callout |
| 18 | |
| 19 | --- |
| 20 | |
| 21 | ## Subjects |
| 22 | |
| 23 | → https://docs.nats.io/nats-concepts/subjects |
| 24 | |
| 25 | ``` |
| 26 | service.orders.created # exact (publishers always use exact subjects) |
| 27 | service.orders.* # * = one token (subscribers only) |
| 28 | service.orders.> # > = one or more tokens at end (subscribers only) |
| 29 | ``` |
| 30 | |
| 31 | - Dot-separated hierarchy; max 16 tokens, <256 chars recommended |
| 32 | - Alphanumeric, `-`, `_` only (avoid other special chars) |
| 33 | - `$` prefix reserved for system use (`$SYS.*`, `$JS.*`, `$KV.*`, `$SRV.*`) |
| 34 | - Multiple overlapping subs on one connection → duplicate delivery per matching sub |
| 35 | |
| 36 | --- |
| 37 | |
| 38 | ## Core NATS Patterns |
| 39 | |
| 40 | → https://docs.nats.io/nats-concepts/core-nats |
| 41 | |
| 42 | ### Pub/Sub |
| 43 | Fan-out to all subscribers. Zero config — subjects are ephemeral. |
| 44 | |
| 45 | ```go |
| 46 | nc.Publish("orders.created", data) |
| 47 | nc.Subscribe("orders.*", func(msg *nats.Msg) { /* handle */ }) |
| 48 | ``` |
| 49 | |
| 50 | → https://docs.nats.io/nats-concepts/core-nats/pubsub |
| 51 | |
| 52 | ### Request/Reply |
| 53 | Requester sends to a subject with a temp reply-to inbox (`_INBOX.<nonce>`). First responder wins. |
| 54 | |
| 55 | ```go |
| 56 | msg, err := nc.Request("svc.lookup", payload, 2*time.Second) |
| 57 | // err == nats.ErrNoResponders when no subscriber (immediate 503) |
| 58 | ``` |
| 59 | |
| 60 | ```go |
| 61 | nc.Subscribe("svc.lookup", func(msg *nats.Msg) { msg.Respond(result) }) |
| 62 | ``` |
| 63 | |
| 64 | → https://docs.nats.io/nats-concepts/core-nats/reqreply |
| 65 | |
| 66 | ### Queue Groups |
| 67 | Competitive consumers — one random member gets each message. Scale horizontally with zero reconfiguration. Geo-affinity: local consumers served first. |
| 68 | |
| 69 | ```go |
| 70 | nc.QueueSubscribe("orders.created", "order-processors", handler) |
| 71 | ``` |
| 72 | |
| 73 | → https://docs.nats.io/nats-concepts/core-nats/queue |
| 74 | |
| 75 | --- |
| 76 | |
| 77 | ## JetStream |
| 78 | |
| 79 | → https://docs.nats.io/nats-concepts/jetstream |
| 80 | |
| 81 | Enable on server: add `jetstream {}` block or pass `--jetstream` flag. |
| 82 | |
| 83 | ### Streams |
| 84 | |
| 85 | Streams persistently capture Core NATS subjects. Configuration is separate from consumption. |
| 86 | |
| 87 | ```go |
| 88 | js, _ := nc.JetStream() |
| 89 | js.AddStream(&nats.StreamConfig{ |
| 90 | Name: "ORDERS", |
| 91 | Subjects: []string{"orders.>"}, |
| 92 | Storage: nats.FileStorage, // or MemoryStorage |
| 93 | Replicas: 3, // clustered only; 1, 2, 3, or 5 |
| 94 | Retention: nats.LimitsPolicy, // default |
| 95 | MaxAge: 24 * time.Hour, |
| 96 | MaxBytes: 1 << 30, |
| 97 | }) |
| 98 | ``` |
| 99 | |
| 100 | **Retention policies** (see [`references/jetstream.md`](references/jetstream.md) for decision tree): |
| 101 | |
| 102 | | Policy | Behavior | |
| 103 | |--------|----------| |
| 104 | | `LimitsPolicy` | Retain until age/size/count limits hit (default) | |
| 105 | | `WorkQueuePolicy` | Delete on ack; one consumer per subject | |
| 106 | | `InterestPolicy` | Retain while consumers have unread messages | |
| 107 | |
| 108 | → https://docs.nats.io/nats-concepts/jetstream/streams |
| 109 | |
| 110 | ### Publishing to JetStream |
| 111 | |
| 112 | **Always use `js.Publish()`** — not `nc.Publish()` — to receive server ack confirming storage. |
| 113 | |
| 114 | ```go |
| 115 | ack, err := js.Publish("orders.created", data) |
| 116 | // ack.Stream, ack.Sequence confirm exactly where it was stored |
| 117 | |
| 118 | // Exactly-once: include Nats-Msg-Id header (dedup window: 2 min default) |
| 119 | js.PublishMsg(&nats.Msg{ |
| 120 | Subject: "orders.created", |
| 121 | Header: nats.Header{"Nats-Msg-Id": []string{uniqueID}}, |
| 122 | Data: data, |
| 123 | }) |
| 124 | ``` |
| 125 | |
| 126 | ### Consumers |
| 127 | |
| 128 | **Prefer pull consumers for new projects.** Use push only for ordered replay with a single subscriber. |
| 129 | |
| 130 | ```go |
| 131 | // Durable pull consumer |
| 132 | js.AddConsumer("ORDERS", &nats.ConsumerConfig{ |
| 133 | Durable: "order-worker", |
| 134 | FilterSubject: "orders.created", |
| 135 | AckPolicy: nats.AckExplicitPolicy, |
| 136 | DeliverPolicy: nats.DeliverAllPolicy, |
| 137 | MaxDeliver: 5, |
| 138 | AckWait: 30 * time.Second, |
| 139 | }) |
| 140 | |
| 141 | su |