Searching and listing
The query command lists objects of a given type, with optional filters and a choice of columns. Results are paginated automatically and can be emitted as a human-friendly table or as a JSON array.
Synopsis
stalwart-cli query <object> [--where key=value]... [--fields a,b,c] [--json]
<object>: object type name, with or without thex:prefix, case-insensitive. Singletons are rejected (usegetinstead).--where: filter clause (repeatable). The supported operator forms are described below.--fields: comma-separated list of properties to return. When omitted, the default columns from the object's list (or from any view targeting it) are used, with anIdcolumn prepended.--json: emit a JSON array (one entry per matching object) instead of the human-friendly table.
Default columns
Without --fields, the CLI uses the column set declared by the object's list, which mirrors what the web UI shows. An Id column is always prepended so each row is addressable by get, update, or delete.
stalwart-cli query domain
Id Domain Name Enabled Certificate Management DNS Management
b example.org Yes Manual TLS certificate management Manual DNS management
c foo.com Yes Manual TLS certificate management Manual DNS management
d bar.com No Manual TLS certificate management Manual DNS management
For multi-variant fields (such as Certificate Management), the variant's friendly label is rendered. Single-variant embedded objects are summarised as <object>. Lists and maps with object values are summarised as <list:N> and <map:N> to keep the table compact.
Selecting columns
When --fields is supplied, those exact columns are shown (still with their friendly labels resolved from the schema's forms or list definitions):
stalwart-cli query domain --fields id,name,isEnabled,createdAt
id Domain Name Enabled Created At
b example.org Yes 2026-04-15T18:13:35Z
c foo.com Yes 2026-04-15T18:17:54Z
d bar.com No 2026-04-15T18:17:54Z
Property names are matched case-insensitively and rewritten to the canonical case before sending. Unknown names are rejected with an error.
Filtering
Filters are passed as --where field<op>value. Multiple --where flags are AND-ed together (JMAP's filter object only supports a single conjunction).
| Operator | Translates to |
|---|---|
= | exact match (the default JMAP filter key) |
>= | <field>IsGreaterThanOrEqual |
<= | <field>IsLessThanOrEqual |
> | <field>IsGreaterThan |
< | <field>IsLessThan |
Comparison operators (>, >=, <, <=) are only valid for number and datetime fields. The CLI rejects them on other types when the field is known to the schema.
stalwart-cli query log --where namespace=surbl-hashbl --fields key,isGlobPattern
key Glob Pattern
0ven.io No
1drv.ms No
1kb.link No
...
For an enum filter:
stalwart-cli query log --where level=error --fields timestamp,event,details
For a numeric range:
stalwart-cli query trafficstat --where receivedCount>=1000 --fields domainId,receivedCount
Repeating the same --where field overrides the previous value (filters are single-valued by definition); duplicates are not an error.
To list which filters an object supports, run describe <object>. The Filters: section lists each accepted key, its kind, and a label.
JSON output
stalwart-cli query domain --fields id,name --json
[{"name":"example.org","id":"b"},{"name":"foo.com","id":"c"},{"name":"bar.com","id":"d"}]
--json fetches every matching page across all pages and emits a single array. Without --fields, the array contains just the ids.
The output is compact (no pretty printing). Pipe to jq for processing:
stalwart-cli query account --fields id,name,domainId --json \
| jq '.[] | select(.domainId=="b") | .name'
Pagination
Internally the CLI uses anchor-based pagination (the JMAP-recommended approach for stable cursors). One JMAP page returns up to maxObjectsInGet rows (typically 500). The CLI then displays them ten at a time, prompting Show more? [Y/n] between batches when stdout is a TTY:
... 10 rows ...
Show more? [Y/n] y
... next 10 rows ...
Press n (or no) to stop. Anything else (including just Enter) continues. When a batch boundary is reached, the next JMAP page is fetched transparently.
When stdout is not a TTY (for example, piping to a file or another command), no prompt is shown and all results stream out.
Tips
- Long cell values are truncated to 60 visible characters with a trailing ellipsis to keep column widths from blowing up. The full value is always available with
--json. - The
Idcolumn added to default listings is the lower-caseid; explicit--fields idkeeps the case as supplied. - For very large result sets where only counts matter,
queryfollowed bywc -l(id-only mode) is the cheapest way to count:stalwart-cli query log | wc -l.
See also
- Fetching a single object for full per-object detail.
- Removing objects, often combined with the ids returned here.
- Declarative bulk operations for filter-driven destroys at scale.