Leaf
Create a separate NATS server that uses a JetStream domain, to be used as a leaf node
Initialize a local nsc config for the leaf node.
❯ make init-leaf-nsc
❯ tree -L2 .nsc
.leaf
├── creds
│ └── leaf
├── keys
│ ├── A
│ ├── O
│ └── U
├── leaf
│ ├── accounts
│ └── leaf.jwt
├── nsc.conf
└── nsc.json
Start leaf node NATS server
Start the leaf node NATS server using the nsc configuration (./.leaf/nsc.conf). Note the leafnodes.remotes value that connects this server to the "local" server:
leafnodes {
remotes = [
{
url: "nats://localhost:7422"
credentials: ".nsc/creds/local/A/admin.creds"
account: "A..."
},
...
]
}
[!NOTE] NKey values will be different in your output.
❯ make leaf
❯ make leaf
nats-server -c leaf.conf
[27274] 2025/08/25 08:35:30.283060 [INF] Starting nats-server
[27274] 2025/08/25 08:35:30.283160 [INF] Version: 2.11.7
[27274] 2025/08/25 08:35:30.283162 [INF] Git: [df44964]
[27274] 2025/08/25 08:35:30.283164 [INF] Name: leaf
[27274] 2025/08/25 08:35:30.283165 [INF] Node: ZLMV550B
[27274] 2025/08/25 08:35:30.283166 [INF] ID: NA7CAQ7BK3UBPNX6BALDGCCRCIFALLDPBQC43AJNX76IHMOA3TMQXLYG
[27274] 2025/08/25 08:35:30.283175 [INF] Using configuration file: leaf.conf (sha256:fcd90964b146f77d21f613fcd03f72b0843495714df49638e57ee093d53f0478)
[27274] 2025/08/25 08:35:30.283179 [INF] Trusted Operators
[27274] 2025/08/25 08:35:30.283180 [INF] System : ""
[27274] 2025/08/25 08:35:30.283181 [INF] Operator: "leaf"
[27274] 2025/08/25 08:35:30.283184 [INF] Issued : 2025-08-25 08:25:36 -0700 PDT
[27274] 2025/08/25 08:35:30.283194 [INF] Expires : Never
[27274] 2025/08/25 08:35:30.283586 [INF] Starting JetStream
[27274] 2025/08/25 08:35:30.283598 [WRN] Temporary storage directory used, data could be lost on system reboot
[27274] 2025/08/25 08:35:30.283859 [INF] _ ___ _____ ___ _____ ___ ___ _ __ __
[27274] 2025/08/25 08:35:30.283863 [INF] _ | | __|_ _/ __|_ _| _ \ __| /_\ | \/ |
[27274] 2025/08/25 08:35:30.283865 [INF] | || | _| | | \__ \ | | | / _| / _ \| |\/| |
[27274] 2025/08/25 08:35:30.283866 [INF] \__/|___| |_| |___/ |_| |_|_\___/_/ \_\_| |_|
[27274] 2025/08/25 08:35:30.283867 [INF]
[27274] 2025/08/25 08:35:30.283868 [INF] https://docs.nats.io/jetstream
[27274] 2025/08/25 08:35:30.283869 [INF]
[27274] 2025/08/25 08:35:30.283870 [INF] ---------------- JETSTREAM ----------------
[27274] 2025/08/25 08:35:30.283877 [INF] Max Memory: 1.00 GB
[27274] 2025/08/25 08:35:30.283880 [INF] Max Storage: 1.00 GB
[27274] 2025/08/25 08:35:30.283881 [INF] Store Directory: "/var/folders/q3/sxmzn9xs6r90xcfzr3g5ch2m0000gn/T/jetstream"
[27274] 2025/08/25 08:35:30.283882 [INF] Domain: leaf
[27274] 2025/08/25 08:35:30.283883 [INF] API Level: 1
[27274] 2025/08/25 08:35:30.283885 [INF] -------------------------------------------
[27274] 2025/08/25 08:35:30.284202 [WRN] Account fetch failed: account missing
[27274] 2025/08/25 08:35:30.284207 [WRN] Account fetch failed: account missing
[27274] 2025/08/25 08:35:30.284743 [INF] Listening for client connections on 0.0.0.0:4223
[27274] 2025/08/25 08:35:30.284873 [INF] Server is ready
[27274] 2025/08/25 08:35:30.286881 [INF] 127.0.0.1:7422 - lid:6 - Leafnode connection created for account: ABIV654V3C2AS4Y6NMZDPHVVOERHABHMBXNS2PFVSQQSGW6QIOQWR6FR/A
[27274] 2025/08/25 08:35:30.289002 [INF] 127.0.0.1:7422 - lid:6 - JetStream using domains: local "leaf", remote ""
^C[27274] 2025/08/25 08:35:35.798395 [INF] Trapped "interrupt" signal
[27274] 2025/08/25 08:35:35.798677 [INF] Initiating Shutdown...
[27274] 2025/08/25 08:35:35.798705 [INF] Initiating JetStream Shutdown...
[27274] 2025/08/25 08:35:35.798718 [INF] JetStream Shutdown
[27274] 2025/08/25 08:35:35.798851 [INF] 127.0.0.1:7422 - lid:6 - Leafnode connection closed: Server Shutdown - Account: ABIV654V3C2AS4Y6NMZDPHVVOERHABHMBXNS2PFVSQQSGW6QIOQWR6FR/A
Create clones of streams from the self-managed cluster into the leaf node
The streams in the leaf node will use “limits” retention policies, which is required for sourcing/mirroring. Interest and work queue policies are not supported when sourcing/mirroring.
❯ cd ./tf/leaf
❯ terraform apply -auto-approve # or `terraform plan -out plan.out` and `terraform apply plan.out`
jetstream_stream.QUEUE: Refreshing state... [id=JETSTREAM_STREAM_QUEUE]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# jetstream_stream.QUEUE will be created
+ resource "jetstream_stream" "QUEUE" {
+ ack = true
+ allow_direct = true
+ allow_msg_ttl = false
+ allow_rollup_hdrs = false
+ compression = "none"
+ deny_delete = false
+ deny_purge = false
+ discard = "old"
+ discard_new_per_subject = false
+ duplicate_window = 120
+ id = (known after apply)
+ max_age = 86400
+ max_bytes = 10485760
+ max_consumers = -1
+ max_msg_size = -1
+ max_msgs = 1024
+ max_msgs_per_subject = -1
+ name = "QUEUE"
+ replicas = 1
+ retention = "limits"
+ storage = "file"
+ subjects = [
+ "QUEUE.>",
]
}
Plan: 1 to add, 0 to change, 0 to destroy.
jetstream_stream.QUEUE: Creating...
jetstream_stream.QUEUE: Creation complete after 0s [id=JETSTREAM_STREAM_QUEUE]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
View the created stream.
❯ nats --server nats://localhost:4223 --creds ../../.leaf/creds/leaf/A/leaf.creds stream report
Obtaining Stream stats
╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Stream Report │
├────────┬─────────┬───────────┬───────────┬──────────┬───────┬──────┬─────────┬───────────┬──────────┤
│ Stream │ Storage │ Placement │ Consumers │ Messages │ Bytes │ Lost │ Deleted │ API Level │ Replicas │
├────────┼─────────┼───────────┼───────────┼──────────┼───────┼──────┼─────────┼───────────┼──────────┤
│ QUEUE │ File │ │ 0 │ 0 │ 0 B │ 0 │ 0 │ 0 │ │
╰────────┴─────────┴───────────┴───────────┴──────────┴───────┴──────┴─────────┴───────────┴──────────╯