Skip to content

Search and Discovery

Three distinct tools, each answering a different question. Picking the wrong one is the most common KV mistake:

  • list browses key names - by prefix, tag, owner, or a substring of the key path.
  • search runs full-text search over values - but only values that were written with indexed.
  • stats aggregates counts and sizes under a prefix.

Listing keys

snug kv list --prefix config/
snug kv list --prefix config/ --depth 0          # immediate children only
snug kv list --filter 'tags[eq]=ui' --filter 'private[eq]=true' --mine
snug kv list --prefix logs/ --sort -updated_at --limit 50   # then --cursor <page.next_cursor>, or --all
snug kv list -q "session" --prefix cache/        # substring on key NAMES

The JSON payload is a keys array of metadata (no values) plus the standard page object; captured live:

{
  "keys": [
    {
      "key": "docs/indexed",
      "content_type": "application/json",
      "size_bytes": 33,
      "owner": "docs-writer",
      "private": false,
      "tags": [],
      "created_at": "2026-08-28T03:48:16.356982Z",
      "updated_at": "2026-08-28T03:48:16.356982Z"
    }
  ],
  "page": { "has_more": false }
}

list speaks the standard list contract: filters on tags, owner, private, content_type, namespace, size_bytes, expires_at, created_at, and updated_at, sorts on created_at (newest first by default), updated_at, and size_bytes, and 25 entries per page by default. prefix and depth stay named parameters, and --mine (mine=true) keeps only your own keys. Other users' private keys simply do not appear. With --depth, keys deeper than that fold into namespace entries, the entries are ordered by key, and the page counts entries rather than keys.

Full-text search over values

Only values written with --indexed are searchable, and indexing is not retroactive - re-set a key to index it. Verified: two keys with identical content, one indexed, and search returns only the indexed one.

snug kv set docs/indexed '{"content":"searchable words here"}' --indexed
snug kv search -q "searchable words" --prefix docs/
{
  "results": [
    {
      "key": "docs/indexed",
      "snippet": "searchable words here",
      "score": 1.0,
      "content_type": "application/json",
      "tags": [],
      "updated_at": "2026-08-28T03:48:16.356982Z"
    }
  ],
  "page": { "has_more": false }
}

search takes the same filters and paging as list, plus prefix.

Remember the split: list -q "dark" will not find {"theme":"dark"} - it looks at key paths, not value bodies. That is what search is for.

Aggregate stats

snug --output json kv stats --prefix docs/
{
  "total_keys": 5,
  "total_size_bytes": 132,
  "keys_by_namespace": { "docs": 5 },
  "keys_by_content_type": { "application/json": 5 },
  "keys_with_ttl": 0,
  "private_keys": 1,
  "indexed_keys": 1
}

A scripting pattern

List, review, then batch-delete - JSON mode prints the bare payload, so fields are addressed directly:

snug --output json kv list --filter 'tags[eq]=deprecated' --mine --all \
  | jq -r '.keys[].key' | tee /tmp/to-delete.txt
# review, then:
snug kv batch-delete "$(paste -sd, /tmp/to-delete.txt)" --force

The exact parameters are in the KV Store API reference.