Skip to main content

Search

The search API takes an input string and attempts to parse it into a structured form with semantics defined below, but falls back to free-text fuzzy search.

Term Structure​

A search term can have up to four components:

[[<entity>@]<attribute>:[<operator>]]<value>
  • value — The minimum required component. Without any qualifier, the value is treated as a free-text search against a predefined set of string attributes across all applicable entities. A value can be quoted to allow whitespace; quotes can be escaped with \".
  • attribute — Qualifies the value against an explicit attribute. An attribute can span multiple entities (e.g. name matches server, stream, consumer, etc.). Every attribute has an associated type and the value is parsed accordingly.
  • operator — An explicit comparison operator for the attribute. Each type has a set of allowed operators. All operators take a single value except .. (between), which takes two, and the implicit is set operator, which takes none.
  • entity — Fully qualifies the term by binding the attribute to a specific entity type.

Examples​

nats-1 # free-text: matches name, id, cluster, ip, etc.
name:nats-1 # attribute: name equals "nats-1" (ILIKE) across all entities with name
server@name:nats-1 # entity + attribute: only match servers
rtt:>100ms # duration comparison: rtt greater than 100ms
rtt:20ms..40ms # range: rtt between 20ms and 40ms (inclusive)
in_bytes:>1gib # byte comparison: more than 1 GiB received
name:"With Spaces" # quoted value with spaces
cpu:>80.5 # float comparison
is_mirror:true # boolean match
description: # is set: the attribute holds a value, whatever it is
metadata.env:prod # label: the entity is labelled env=prod
metadata.env: # label: the entity carries an env label at all
NOT slow_consumers:>0 # negation
(name:foo OR name:bar) rtt:<10ms # grouping with implicit AND

Multiple Terms​

  • Terms are combined with logical operators: AND, OR, and NOT
  • Without an explicit operator, adjacent terms are implicitly ANDed
  • Grouping with parentheses () overrides default precedence
  • Precedence (lowest to highest): OR < AND < NOT
  • AND, OR, and NOT are keywords in either case: and and AND both apply. A value that would otherwise read as one is reachable by quoting it.

Value Types​

Every attribute has one of the following types. The value in a search term must be parseable as its attribute's type.

string​

Plain text. String equality uses case-insensitive matching (ILIKE). Supports =, !=, and ~ (like) operators.

int​

Integer number. Supports =, !=, >, >=, <, <=, and .. (between).

float​

Floating-point number. Supports the same operators as int.

bool​

Boolean value: true or false. Supports = and !=.

duration​

A number with a time unit suffix. Stored internally as nanoseconds. Supports the same operators as int.

UnitSuffix
Nanosecondns
Microsecondus, µs
Millisecondms
Seconds
Minutem
Hourh
Dayd

bytes​

A number with a byte size unit suffix (IEC binary units, powers of 1024). Supports the same operators as int.

UnitSuffix
Byteb
Kibibytekib
Mebibytemib
Gibibytegib
Tebibytetib

SI suffixes (kb, mb, gb, tb) are not accepted. Use the IEC equivalents above.

timestamp​

An ISO-8601 date or datetime value. Supports the same operators as int (for ordering and range comparisons).

Examples: 2024-01-15, 2024-01-15T10:30:00Z

string[]​

An array of strings. Matched using the same operators as string — the comparison checks if any element in the array matches.

Example: tags:nats-server matches any entity whose tags array contains an element matching nats-server.

Operators​

Not all operators apply to all types. The table below shows which operators are valid for each type.

OperatorSyntaxstringstring[]intfloatdurationbytestimestampbool
Equal(implicit)YYYYYYYY
Not equal!=YYYYYYYY
Greater than>YYYYY
Greater or equal>=YYYYY
Less than<YYYYY
Less or equal<=YYYYY
Between..YYYYY
Like~YY
Is set(no value)YYYYYYYY

String equality (=) is case-insensitive (ILIKE). The ~ operator performs an ILIKE substring match.

An attribute with nothing after the colon — description: — asks whether it holds a value. An empty string does not count as set for a string, nor an empty list for a string[]. Writing an operator without its value, such as rtt:>, remains an error: the operand is missing, not omitted.

Entities​

There are 13 searchable entity types. Each reads the tables below at the single epoch described under Query Semantics.

Each entity's view selects every attribute listed for it below; an attribute is never advertised without a column behind it.

The account and user views are assembled from the columns a query actually names, rather than being one fixed subquery. A view is a subquery in the FROM clause, and DuckDB drops the columns a query does not select while keeping the joins that produce them — so an aggregate nobody asked for is still computed and then discarded. Against production data the account view's subscription count, which reaches sub_stats through two identity tables, cost roughly a second on a search whose only result columns were a primary key and a name; leaving it out brings that query to well under a tenth of that. Adding a column to one of those views therefore means adding it to the join's column list too, which the entity view test enforces by reading the assembled view's real columns.

EntityReadsEpoch-scoped
serverhx.server_stats + ident and optsYes
clusterhx.server_stats aggregated per clusterYes
accounthx.account_ident + opts, stats and subscription countsIdentity kept, values at the epoch
userhx.user_ident + opts and connection countsIdentity kept, values at the epoch
connectionhx.conn_stats + ident, with account, server and user namesYes
streamhx.stream_replica_stats leader rows + ident and optsYes
kvstorethe same, for KV-backing streamsYes
objectstorethe same, for object-store-backing streamsYes
service$SRV.INFO subscriptions in hx.sub_ident, one row per account and service nameYes
consumerhx.consumer_replica_stats leader rows + ident and optsYes
leafhx.leafsYes
routehx.routesYes
gatewayhx.gatewaysYes

Attributes​

Cross-Entity Attributes​

These attributes appear on multiple entities. Using one without an entity qualifier searches all entities that have it.

AttributeTypeserverclusteraccountuserconnectionstreamkvstoreobjectstoreserviceconsumerleafroutegateway
namestringYYYYYYYYY
accountstringYYYYYYY
ipstringYYYYY
clusterstringYYYYYY
rttdurationYYYY
in_msgsintYYYY
out_msgsintYYYY
in_bytesbytesYYYY
out_bytesbytesYYYY
num_subsintYYYY
versionstringYY
descriptionstringYYYY
checkstringYYYYYYYYYY

The check attribute filters entities by check code (e.g., check:server-003). It matches against materialized check findings for that entity. On the streams page, a check filter also lists the KV and object-store backing streams the check fired on. The unfiltered listing leaves those to their own pages. A stream check's count on the system page includes them, so the filtered list matches that count.

Server Attributes​

AttributeType
idstring
hoststring
coresint
portint
start_timetimestamp
tagsstring[]
git_commitstring
go_versionstring
system_accountstring
config_load_timetimestamp
auth_requiredbool
auth_timeoutduration
tls_requiredbool
tls_verifybool
max_payloadbytes
max_pendingbytes
max_control_lineint
max_connectionsint
ping_intervalduration
ping_maxint
write_deadlineduration
http_hoststring
http_portint
https_portint
http_base_pathstring
leaf_hoststring
leaf_portint
leaf_auth_timeoutduration
leaf_tls_timeoutduration
js_domainstring
js_max_memorybytes
js_max_storebytes
js_store_dirstring
js_sync_intervalduration
js_sync_alwaysbool
js_compress_okbool
js_unique_tagstring
memorybytes
cpufloat
connectionsint
subscriptionsint
routesint
leafsint
gatewaysint
js_memorybytes
js_storagebytes
slow_consumersint
ha_assetsint
total_connectionsint
stale_connectionsint
stalled_clientsint
remotesint
js_reserved_memorybytes
js_reserved_storagebytes
js_api_totalint
js_api_errorsint
js_api_inflightint

Cluster Attributes​

AttributeType
clusterstring
serversint
cpufloat
memorybytes
connectionsint
ha_assetsint

servers, cpu, memory, connections and ha_assets are aggregates over the cluster's servers at the epoch, matching the clusters table: servers counts them, cpu averages per-core utilization, and the rest are sums. A cluster result is one row per cluster, not one per server.

Account Attributes​

AttributeType
is_systembool
jetstream_enabledbool
connsint
subsint
msgs_sentint
msgs_recvint
leafnodesint
slow_consumersint
expiredbool
completebool
num_exportsint
num_importsint
issuer_keystring
labelstring
tagsstring[]
max_subsint
max_databytes
max_payloadbytes
max_connint
max_leaf_connint
max_importsint
max_exportsint
js_mem_storagebytes
js_disk_storagebytes
js_max_streamsint
js_max_consumersint
js_max_ack_pendingint
last_updatetimestamp
total_connsint
bytes_sentbytes
bytes_recvbytes
route_bytes_sentbytes
route_bytes_recvbytes
route_msgs_sentint
route_msgs_recvint
gateway_bytes_sentbytes
gateway_bytes_recvbytes
gateway_msgs_sentint
gateway_msgs_recvint
leaf_bytes_sentbytes
leaf_bytes_recvbytes
leaf_msgs_sentint
leaf_msgs_recvint

User Attributes​

AttributeType
accountstring
bearerbool
name_tagstring
connectionsint
issuer_accountstring
tagsstring[]
last_updatetimestamp

Connection Attributes​

AttributeType
kindstring
typestring
langstring
tls_versionstring
uptimeduration
idleduration
bytes_sentbytes
bytes_recvbytes
msgs_sentint
msgs_recvint
pending_bytesbytes
idint
portint
tls_cipherstring
mqtt_clientstring
start_timetimestamp
last_activitytimestamp
stop_timetimestamp
reasonstring
stallsint
serverstring
userstring

Stream Attributes​

AttributeType
created_attimestamp
storage_typestring
retention_policystring
max_bytesbytes
max_msgsint
max_ageduration
num_replicasint
is_mirrorbool
discard_policystring
sealedbool
subjectsstring[]
placement_clusterstring
placement_tagsstring[]
max_msg_sizebytes
deny_deletebool
deny_purgebool
allow_directbool
max_consumersint
max_msgs_per_subjectint
deduplication_windowduration
config_first_seqint
discard_new_perbool
allow_rollupbool
no_ackbool
consumer_inactive_thresholdduration
consumer_max_ack_pendingint
mirror_namestring
mirror_api_prefixstring
num_sourcesint
store_compressionstring
has_subject_transformbool
has_republishbool
msgsint
bytesbytes
num_subjectsint
num_consumersint
first_seqint
last_seqint
first_tstimestamp
last_tstimestamp
num_deletedint
mirror_lagint
mirror_activeduration
mirror_errorstring

KV Store Attributes​

AttributeType
storage_typestring
num_replicasint
keysint
bytesbytes
historyint
ttlduration
max_bytesbytes
sealedbool
deny_deletebool
deny_purgebool
allow_directbool
store_compressionstring
num_consumersint

Object Store Attributes​

AttributeType
storage_typestring
num_replicasint
msgsint
bytesbytes
max_bytesbytes
sealedbool
store_compressionstring
num_consumersint

Service Attributes​

The services overview aggregates connections into one row per (account, service name), so per-connection attributes (lang, version, ip) have no single value to filter on and are not exposed on the service entity. To filter by those, query the connection entity.

AttributeType
service_namestring
accountstring
instancesint

Consumer Attributes​

AttributeType
streamstring
created_attimestamp
deliver_policystring
ack_policystring
ack_waitduration
max_deliverint
max_ack_pendingint
inactive_thresholdduration
replay_policystring
heartbeatduration
opt_start_seqint
opt_start_timetimestamp
max_waitingint
max_batchint
max_expiresduration
max_bytesbytes
deliver_subjectstring
deliver_groupstring
flow_controlbool
headers_onlybool
num_replicasint
storage_typestring
filter_subjectsstring[]
sample_frequencystring
memory_storagebool
priority_policystring
num_ack_pendingint
num_redeliveredint
num_waitingint
num_pendingint
delivered_stream_seqint
delivered_consumer_seqint
ack_floor_stream_seqint
ack_floor_consumer_seqint
pausedbool
pause_remainingduration
push_boundbool

Leaf Attributes​

AttributeType
is_spokebool
compressionstring
idint
portint
is_isolatedbool
subsstring[]

Route Attributes​

AttributeType
uptimeduration
idleduration
pending_sizebytes
did_solicitbool
is_configuredbool
compressionstring
start_timetimestamp
last_activitytimestamp
stallsint

Gateway Attributes​

AttributeType
uptimeduration
idleduration
pending_sizebytes
is_outboundbool
is_configuredbool
tls_versionstring
tls_cipherstring
authorized_userstring
start_timetimestamp
last_activitytimestamp
stallsint

Labels​

Servers, streams, consumers, KV stores, and object stores carry operator-assigned metadata — the labels set on the NATS resource itself. Because their keys are arbitrary, they are addressed by path rather than being listed among the entity's attributes:

metadata.<key>:<value>
metadata.env:prod # labelled env=prod
metadata.env: # labelled env, whatever the value
metadata.env:!=prod # labelled env, but not prod
stream@metadata.io.nats.monitor.enabled:true

A key is matched exactly and is case-sensitive, and dots in a key are part of the key rather than a path into nested JSON — metadata.io.nats.monitor.enabled names one label. Labels are text, so they take the string operators; an ordering operator against one is rejected the same way it is against any other text attribute.

Negation needs the label present: metadata.env:!=prod selects entities labelled with something other than prod, not every entity that is not labelled prod. To reach the unlabelled ones as well, negate the whole term with NOT metadata.env:prod.

In a table's filter box, an entity that carries no metadata reports metadata.<key> as an attribute it does not have, the same as any other unknown attribute. The global search bar resolves a label term only with an entity qualifier, as in stream@metadata.env:prod; unqualified, it answers that no entities match.

Autocomplete reads the keys and values from the data rather than from a fixed list, ranked by how many entities carry them.

Stages​

An expression can end in stages, each introduced by a | with whitespace on both sides, that arrange the rows the filter selected rather than select them:

metadata.env:prod | by region | sort health desc
  • | by <key> groups rows under the value of a label, with an aggregate header per group. Rows without the label group under "no value", last. When several by stages are written, the last one applies.
  • | sort <attr> [desc] orders rows by a column or a label. Sort stages stack left to right, so | sort tier | sort name is a two-level ordering. Anything other than desc sorts ascending.

The Systems and Nodes lists apply stages; a notice under their filter says which stage or attribute it ignored. Entity table filter boxes and their previews drop the stages and apply the filter before them. The global search bar does not accept stages.

A | without surrounding whitespace, as in orders.a|b, is part of the value.

When a value is provided without an attribute or entity qualifier, it is treated as a free-text search. The value is matched (case-insensitive substring via ILIKE) against these attributes on every entity that has at least one of them:

name, service_name, id, cluster, ip, host, version, lang, description, go_version, label, reason, tls_cipher, mqtt_client, js_domain, mirror_name, server, user

For example, searching nats-1 checks the name, id, cluster, ip, host, version, go_version and js_domain columns on the server entity; the name, cluster, ip, version, lang, reason, tls_cipher, mqtt_client, server and user columns on the connection entity; and so on for each entity.

Fuzzy Suggestions​

When a search query references an unknown entity or attribute name, the system attempts to suggest corrections instead of returning a generic error.

How It Works​

  1. The parsed AST is validated against the registry of known entities and attributes
  2. Unknown names are compared against valid candidates using Levenshtein distance and prefix matching
  3. The adaptive threshold is max(1, len(name)/3) — shorter names allow fewer edits
  4. At most 3 suggestions are returned, sorted by edit distance (closest first)

Examples​

servr@name:foo → "Did you mean: server" (entity misspelling)
nme:foo → "Did you mean: name" (attribute misspelling)

Suggestions appear as clickable items in the search dropdown. Clicking a suggestion replaces the query with the corrected version and re-executes the search.

Behavior​

  • Suggestions only appear when a query fails to resolve because of an unknown entity or attribute name
  • If no close matches are found, the original error is shown
  • Valid queries produce normal results with no suggestions

Dropped Filters​

A per-table filter naming an attribute the table's entity does not have cannot be turned into a query, and the table shows every row. A notice under the filter box reads Filter not applied followed by the reason, with correction chips drawn from the attributes that entity actually has. The whole filter is dropped, not just the offending term.

When a single bare word falls back to free-text matching, the notice says so too, so a substring match is never mistaken for an exact one.

Query Semantics​

Once parsed into an AST, the search expression is evaluated as follows:

  1. Entity resolution — The parser determines which entities can satisfy the expression. If a term references a specific entity (e.g. server@name:foo), only that entity is queried. If a term references an attribute without an entity, all entities with that attribute are candidates. Free-text terms match all entities that have at least one free-text attribute. For AND, entity sets are intersected; for OR, they are unioned.

  2. Fan-out — A separate SQL query is generated for each resolved entity. Each query selects the pk and matched columns from the entity's view.

  3. Epoch scoping — The query reads a single epoch: the one the page's time controls resolve to. A live page reads the latest epoch; a pinned or stepped page reads the epoch it is showing, so a search finds what existed then rather than what exists now. Accounts and users are the exception in one direction only: their identity is retained, so one that has stopped reporting is still findable by name, while the values shown beside it are those of the resolved epoch.

  4. Parameterized queries — All user values are passed as parameterized query arguments, not interpolated into SQL.

  5. Result limit — Each entity query returns at most 10 rows, alongside the total number of matches for that entity.

Match Context​

Every attribute an expression names is shown beneath each result, in the order it was written, so a row says why it matched rather than only that it did:

server@subscriptions:>50000

nats-east-1 subscriptions: 52,341
nats-east-2 subscriptions: 51,090
  • Every named attribute appears, not only the ones a given row satisfies. Under OR this is what tells the two halves apart: a row answering subscriptions:>50000 OR connections:>1000 shows both numbers, and the reader sees which one put it in the list.
  • A NULL shows as a dash. For NOT js_domain: the absent value is the reason the row matched.
  • Values are formatted by type — counts with thousands separators, sizes in IEC units, durations, and dates.
  • The displayed name is never repeated underneath itself, and a check: term adds nothing, because its value is the code in the term.
  • A free-text match leads. When a bare word matched a column other than the name, that column and value come first, ahead of the attributes named explicitly.

Values come from the same query that selected the rows, so no extra lookup is made per result.

Table Filter Preview​

The per-table filter box shows the first five rows its filter would select, and how many there are, before Enter applies it. It reads the entity's own view rather than the table's, so attributes the table has no column for still show their values, and it carries the tab's scope and the page's epoch.

Nothing is previewed for a filter the table would not apply — the notice under the input already says why.