README
¶
nats-tui — a terminal front-end to nats
nats-tui is a Go + bubbletea /
huh front-end to
nats, the NATS command-line tool. It
shows the server a nats context points at as a tree — the JetStream
streams with their consumers, the key-value buckets, the object stores, the
micro services answering discovery — opens everything in dialog-style
editors, and drives nats for every change: each action becomes a plan of
nats commands that is previewed, confirmed, run and followed by a re-read
of the server. Messages are published, requested and watched live from the
same screens. Nothing is ever changed except through nats itself, so the
preview is exactly what you could type in a shell.

It is the sibling of nsc-tui, which does
the same for nsc, and shares its look and keys.
go install github.com/olgeni/nats-tui@latest # or: go build -o nats-tui .
nats-tui # nats's selected context
nats-tui -context prod # a named context (nats --context)
nats-tui -s nats://localhost:4222 # a server, no context
nats-tui -mouse # with mouse support (m toggles it at runtime)
nats-tui -refresh 5s # re-read the server every 5s (ctrl+r toggles it)
nats-tui -json | jq '.streams[].config.name' # non-interactive dump; -tree for a text listing
go test ./... # unit tests + server-backed tests (skipped without nats-server)
man ./nats-tui.1 # manual page
Main screen
The tree has the context on top, then the streams (a stream expands into its consumers), the key-value buckets, the object stores and the services. The header shows the server, its version and cluster, the round-trip time, the JetStream usage of the account and the credentials in use.
| Key | Action |
|---|---|
↑/↓ j/k pgup/pgdn home/end |
move |
→ / ← / space / * |
expand / collapse a stream or a section (*: all) |
/ |
filter by name, subject or description (esc clears) |
enter |
details of the entity (a service is also asked for its request statistics); J toggles its raw JSON |
e |
edit the stream, consumer, bucket, object store or context |
a |
add what the row holds: a consumer (on a stream), a key (on a bucket), a file (on an object store), a bucket or store (on their section), a stream elsewhere |
A |
add a stream |
d / del |
delete the stream, consumer, bucket or object store |
P |
purge a stream: everything, one subject, up to a sequence, or all but the last few |
v |
messages of a stream, one page at a time ([ ] page, g jumps to a sequence, f keeps a subject, d deletes a message); on a bucket its keys, on an object store its objects |
t |
subjects held in a stream with their message counts |
n |
next messages of a pull consumer (nats consumer next), acknowledged, nak'ed, terminated or left alone |
u |
pause / resume a consumer |
K / O |
keys of a bucket (put, edit, history, revert, delete, purge, watch) / objects of an object store (put, get, delete, watch); an edited key is written with nats kv update at the revision it was read at |
s |
subscribe live to a stream's subjects, or to what you type |
p / R |
publish a message (nats pub) / send a request and show the reply (nats request) |
w |
watch a bucket or an object store live |
E |
events: JetStream advisories and metrics, server events |
I |
account information |
M T L |
the menus (see below): monitoring, reports, cluster. Each opens a two-row control panel over the tree |
C |
contexts: list, use, select as default, add, edit, copy, delete, validate |
S |
use another context (every command then carries --context) |
b / B |
backup a stream to a directory, or every stream of the account elsewhere / restore a stream or an account backup |
y |
copy a stream's configuration to a new stream, which needs subjects of its own; on a consumer, copy the consumer |
x |
seal a stream or an object store (irreversible) |
m |
toggle the mouse (or start with -mouse): click a row to select it, click it again to open it, wheel scrolls; in editors a click focuses a field, a second click edits or toggles it; hold shift to select text |
ctrl+r |
auto-refresh: re-read the server every 5 seconds, or the -refresh interval, on the main screen, the details and the tables |
r |
re-read the server |
h / ? |
key map / help, q quit |

The consumers of a stream and the objects of a store are fetched when the stream is expanded or the store opened, one request each, and kept across reloads, so a server with hundreds of streams opens in the time of one stream list. The counts shown before that come from the stream state.
Sealed streams and paused consumers are shown in yellow; consumers are muted under their stream.
Menus
M, T and L open a menu in the manner of the Lotus 1-2-3 control panel:
two rows above the tree, the first holding the items of the level you are in
and the second the items of whichever one is highlighted, so the level below
is read before it is entered.
Monitor Report Check Server Account Rtt
Connections Jetstream Accounts Health Cpu Mem Routes Gateways Leafnodes Downgrade
←→ move along a level, the letter picked out in each word chooses that item
at once, enter or ↓ opens a group or runs a command, esc or ↑ leaves
one level and closes the menu at the top, and the key that opened it closes it
from anywhere. So MT is nats rtt and MSL is nats server list, typed as
fast as the fingers go. Nothing else reaches the tree while a menu is up, and
/ stays the filter.
The accelerator is the first letter of a word unless the item names another
one, which is how Connections and Cpu keep a letter each.
MMonitor — Report (connections, jetstream, accounts, health, cpu, mem, routes, gateways, leafnodes, downgrade), Check, Server (list, info, ping, mappings, account info), Account (info, connections, tls) and Rtt. The server commands need a system account context;rttand the account commands work with any user. Check begins with This, thenats server checkof the selected stream, consumer or bucket, and goes on to jetstream, connection, meta, server, request and credential, the last few behind a small editor for their thresholds.TReports — Streams, Consumers, Account (the three reports), Find (stream find,consumer find), Gaps, and on a service row Service (info, stats).LCluster — the commands for the selected stream or consumer first (Stepdown, Peer; Reset, Unpin), then Balance (streams, consumers), Meta (the JetStream meta group: stepdown, peer), Reload, Kick and Purge. Each one is a plan, previewed and confirmed like the others.
Editors
Every entity is edited in the same kind of dialog: labelled fields moved
with ↑/↓/tab, enter to edit a text field in place (enter keeps,
esc reverts), space for checkboxes, ←/→ for choices, ctrl+s for OK.
Lists (subjects, sources, tags, metadata) are comma-separated; metadata is
written key=value. Limits are -1 for unlimited; sizes take k/m/g/t
(decimal) or kib/mib/gib; durations are 30s, 5m, 2h, 1d,
1w, 1y, blank for none.

Only what changed is passed to nats, and the preview shows the commands:
[1/1] apply the changes (nats shows the difference it applied)
nats --context prod stream edit ORDERS --max-msgs=500 --deny-purge -f

nats stream edit and nats consumer edit print the difference they
applied, which the result screen shows. Some settings are fixed at creation
— a stream's storage, a consumer's pull/push mode and its deliver, ack and
replay policies — and the plan says so in a note rather than sending a flag
the server would refuse. A few nats details the plans know:
- A new stream or consumer is created with
--defaults, sonatsnever prompts; only what differs from its defaults is passed, plus the storage and the subjects. - An unlimited duration is
0on edit (--max-age=0);-1is refused there althoughstream addtakes it. --republish-destinationneeds a--republish-source, so a blank source is sent as>.- A consumer with
--ack=nonecannot carry an ack wait or a pending limit. - Deny delete and deny purge cannot be lifted once set, and neither the storage nor the retention of an existing stream can change: the editor accepts the change, the plan drops it and says so in a note.
- A value or a message body that spans several lines is piped to
nats kv put/nats pub --force-stdinrather than passed as an argument.nats kv updatereads no stdin, so an edited value is passed as an argument, quoted in the preview. nats server checkexits non-zero on a warning or a critical state: that is the result, and the report is shown all the same.Btells a stream backup (a directory holdingbackup.json) from an account backup (one such directory per stream) and runsnats stream restoreornats account restoreaccordingly.nats pub --schedule-after(nats 0.4.0) sends theNats-Scheduleheader without its@atprefix, which the server refuses (natscli#1719). The flag is only a shorthand for--schedule-atwith the current time plus the delay, so the plan does that computation itself and always sends--schedule-at; this works on every version ofnatsand keeps the preview honest, since no command runs that was not shown. The one cost is that the time is fixed when the plan is built, not when it runs: leave the preview open for a minute and the schedule fires a minute earlier than the delay says. The note on the plan shows the absolute time. Once the fix is released,--schedule-aftercan be sent directly to versions that have it. Cron schedules take six fields, seconds first.
Messages and live screens
v on a stream reads a page of its messages (an ordered consumer, no state
on the server); enter shows one with its headers, JSON indented and
binary hex-dumped. a adds a consumer filtered on the subject shown, from
the messages table or the subjects table. s subscribes to subjects and shows what arrives, w
watches a bucket (every change with its revision, current values first) or
an object store, E follows the JetStream advisories, metrics and server
events. New entries are followed unless you scroll back; end follows
again, / filters by subject or body, c clears, enter opens an entry,
p publishes to its subject, esc stops the subscription. The last 5000
entries are kept.
Every table screen (contexts, messages, subjects, keys, history, objects)
reads its rows once, when it is opened, so a bucket whose keys have a TTL
keeps showing them after they expire. r reads the table again and comes
back to the row you were on.


A message can also be scheduled instead of sent: the publish editor takes a schedule (once at an RFC3339 time, once after a delay, every interval, or on a cron line), the subject it is published to when the schedule fires, an optional source subject whose last message is sent instead of the body, and a TTL for the fired messages. The stream holding the publish subject must allow message schedules, a stream option that, like per-message TTL, cannot be turned off once on. One schedule lives on each subject: a new one replaces it.

Subscriptions run in the client library over the same connection; what
nats sub would print is what the screen shows, without parsing it.
Contexts
A context is a file under ~/.config/nats/context holding a server URL
and credentials; nats uses the selected one unless --context is given.
nats-tui does the same: -context or S uses one, and every command
then carries --context so what runs matches what is shown. C lists
them; enter uses one, S makes it the default, e edits it (nats context add on an existing name keeps what is not given), V validates it
by connecting. Without any connection — a context that does not answer —
the main screen says why and still offers C, S and r.
Non-interactive use
nats-tui -json prints one JSON document with the context, the known
contexts, the connection facts (server id, name, version, cluster, max
payload, RTT), the JetStream account information, every stream with its
configuration, state and consumers, the buckets with their configuration,
the object stores with their objects, and the services. -tree prints the
same as an indented text listing. Both exit 1 only when the server cannot
be reached; a server without JetStream is reported, not an error.
Tests
go test ./... # everything, a few seconds
go test -v ./cli # the server-backed tests, verbose (SKIP without nats-server)
go vet ./...
The server-backed tests start a throwaway nats-server -js on a free port
under t.TempDir(), point a temporary nats context at it (through
XDG_CONFIG_HOME), run the plans the editors would produce through the real
nats, read the result back with the client library and compare — the same
round trip the TUI makes. They skip themselves when nats-server or nats
is not installed. The server runs under a shell holding a pipe from the test
binary and is stopped when the pipe closes, so it does not outlive a test
that is interrupted, times out or is killed.
Documentation
¶
Overview ¶
Command nats-tui is a terminal user interface for nats, the NATS command-line tool: it shows the streams, consumers, buckets and services of a server as a tree, edits them in dialogs, and drives nats for every change, previewing the commands before running them. Messages are published, requested and watched live from the same screens.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package cli drives the nats command-line tool and reads the server it points at.
|
Package cli drives the nats command-line tool and reads the server it points at. |
|
internal
|
|
|
testnats
Package testnats starts a throwaway nats-server for the tests and points a temporary nats context at it, so the server-backed tests never touch a real server or the user's contexts.
|
Package testnats starts a throwaway nats-server for the tests and points a temporary nats context at it, so the server-backed tests never touch a real server or the user's contexts. |