Skip to content
Oeiuwq Faith Blog OpenSource Porfolio

simeji/jid

json incremental digger

simeji/jid.json
{
"createdAt": "2016-06-06T14:28:53Z",
"defaultBranch": "master",
"description": "json incremental digger",
"fullName": "simeji/jid",
"homepage": null,
"language": "Go",
"name": "jid",
"pushedAt": "2026-07-04T13:24:05Z",
"stargazersCount": 7133,
"topics": [
"cli",
"go",
"golang",
"jid",
"json",
"tool"
],
"updatedAt": "2026-07-12T17:26:27Z",
"url": "https://github.com/simeji/jid"
}

Test

jid logo

Json Incremental Digger

It’s a very simple tool. You can drill down JSON interactively by using filtering queries like jq.

Suggestion, Auto completion, and JMESPath support provide a comfortable JSON exploration experience.

Interactively navigate JSON using dot-path queries. Tab-complete fields, cycle through candidates, and see the matching key highlighted in the JSON view in real time.

demo-jid-drilldown

Use pipes, wildcards, and built-in functions directly in the filter. Function candidates are shown with usage hints and argument templates are filled in automatically.

demo-jid-jmespath

  • [With HomeBrew (for macOS)]!(#with-homebrew-for-macos)
  • [With MacPorts (for macOS)]!(#with-macports-for-macos)
  • [With pkg (for FreeBSD)]!(#with-pkg-for-freebsd)
  • [With scoop (for Windows)]!(#with-scoop-for-windows)
  • [Other package management system]!(#other-package-management-systems)
  • [Simply use “jid” command]!(#simply-use-jid-command)
  • [Build]!(#build)
brew install jid
sudo port install jid
pkg install jid
scoop install jid

Jid can install by package management systems of below OS.

Packaging status

If you simply want to use jid command, please download binary from below.

https://github.com/simeji/jid/releases

go install github.com/simeji/jid/cmd/jid@latest
  • [simple json example]!(#simple-json-example)
  • [simple json example2]!(#simple-json-example2)
  • [with initial query]!(#with-initial-query)
  • [with curl]!(#with-curl)

Please execute the below command.

echo '{"aa":"2AA2","bb":{"aaa":[123,"cccc",[1,2]],"c":321}}'| jid

then, jid will be running.

You can dig JSON data incrementally.

When you enter .bb.aaa[2], you will see the following.

[Filter]> .bb.aaa[2]
[
1,
2
]

Then, you press Enter key and output [1,2] and exit.

echo '{"info":{"date":"2016-10-23","version":1.0},"users":[{"name":"simeji","uri":"https://github.com/simeji","id":1},{"name":"simeji2","uri":"https://example.com/simeji","id":2},{"name":"simeji3","uri":"https://example.com/simeji3","id":3}],"userCount":3}}'|jid

First argument of jid is initial query. (Use JSON same as [Demo]!(#demo))

demo-jid-with-query

Sample for using RDAP data.

curl -s http://rdg.afilias.info/rdap/domain/example.info | jid
jid < file.json
keydescription
TAB / CTRL + IShow available items and choose them (cycles forward); highlights the matching key in the JSON view
Shift + TABCycle candidates backward / decrement array index
CTRL + WDelete one JMESPath segment backward (e.g. .id[0]func(@) → pipe)
CTRL + UDelete whole query
CTRL + XToggle function description display (visible when function candidates are shown)
CTRL + F / Right Arrow (:arrow_right:)Move cursor a character to the right
CTRL + B / Left Arrow (:arrow_left:)Move cursor a character to the left
CTRL + ATo the first character of the ‘Filter’
CTRL + ETo the end of the ‘Filter’
CTRL + JScroll json buffer 1 line downwards
CTRL + KScroll json buffer 1 line upwards
CTRL + GScroll json buffer to bottom
CTRL + TScroll json buffer to top
CTRL + NScroll json buffer ‘Page Down’
CTRL + PScroll json buffer ‘Page Up’
CTRL + LChange view mode whole json or keys (only object)
ESCHide a candidate box
Up ArrowNavigate to previous query in history
Down ArrowNavigate to next query in history
optiondescription
First argument ($1)Initial query
-hprint a help
-helpprint a help
-versionprint the version and exit
-qOutput query mode (for jq)
-Mmonochrome output mode

jid can be configured via a TOML file located at:

OSPath
macOS~/Library/Application Support/jid/config.toml
Linux~/.config/jid/config.toml
Windows%AppData%\jid\config.toml
[history]
path = "~/.jid_history" # custom history file path
max_size = 1000 # number of entries to keep
[keybindings]
history_prev = "up" # navigate to older query
history_next = "down" # navigate to newer query
scroll_down = "ctrl+j"
scroll_up = "ctrl+k"
scroll_to_bottom = "ctrl+g"
scroll_to_top = "ctrl+t"
scroll_page_down = "ctrl+n"
scroll_page_up = "ctrl+p"
toggle_keymode = "ctrl+l"
delete_line = "ctrl+u"
delete_word = "ctrl+w"
cursor_left = "ctrl+b"
cursor_right = "ctrl+f"
cursor_to_start = "ctrl+a"
cursor_to_end = "ctrl+e"
toggle_func_help = "ctrl+x"
candidate_next = "tab" # cycle candidates forward
candidate_prev = "ctrl+p" # cycle candidates backward (additional key; Shift+Tab always works)
quit = "ctrl+q" # exit jid (used when exit_on_enter = false)
[behavior]
exit_on_enter = true # set to false to prevent accidental exit on Enter

Note: Shift+Tab (\x1b[Z) is a fixed terminal escape sequence and always triggers backward cycling regardless of candidate_prev.

By default, pressing Enter exits jid and prints the current result. If you find yourself accidentally exiting, set exit_on_enter = false in config.toml:

[behavior]
exit_on_enter = false

When disabled, Enter only confirms a candidate selection. Use Ctrl+Q (or your configured quit key) to exit.

ctrl+actrl+z, up, down, left, right, tab, enter, esc, backspace, home, end, pgup, pgdn, delete, f1f12

Queries are saved automatically on Enter. The history file path follows the same OS convention as the config file (e.g. ~/Library/Application Support/jid/history on macOS) unless overridden in config.toml.

jid supports JMESPath expressions in addition to the traditional dot-path notation. JMESPath mode is automatically activated when the query contains pipe (|), wildcards ([*]), filter expressions ([?), or function calls.

. traditional: show root JSON
.users traditional: navigate to users field
.users[0].name traditional: array index + field access
.users[*].name wildcard projection: extract name from every user
.users[*].address.city nested wildcard projection
.users[*].<Tab> show field candidates from array elements
. | keys(@) pipe: list root object keys
.users | length(@) pipe: count users array
.users | sort_by(@, &name) pipe: sort users by name field
.users | reverse(@) pipe: reverse the array
.[1] | to_array(@)[0].id chained pipe with indexing
. | to_array(@)[0] wrap root in array and index
.users[*].name | [0] project names then index

After a wildcard projection like .game_indices[*].version, the result is an array. Use [N] to navigate into it — jid automatically rewrites to pipe form internally:

.game_indices[*] → field candidates: game_index, version
.game_indices[*].version → shows array of version objects; suggests [
.game_indices[*].version[0] → first version object {name, url}
.game_indices[*].version[0].name → first version's name
.game_indices[*].version[0] | keys(@) → keys of first version object
.game_indices[*].version[0] | keys(@) | sort(@) → sorted keys

Note: In standard JMESPath, [*].field[0] applies [0] to each projected element rather than the projected array, producing []. jid detects this pattern and transparently rewrites it to [*].field | [0] so [0] indexes the array.

When you type | after a field, jid shows available JMESPath functions filtered by the type of the preceding expression:

Input typeSuggested functions
Arrayavg, contains, join, length, map, max, max_by, min, min_by, not_null, reverse, sort, sort_by, sum, to_array, to_string, type
Objectkeys, length, merge, not_null, to_array, to_string, type, values
Stringcontains, ends_with, length, not_null, reverse, starts_with, to_array, to_number, to_string, type
Numberabs, ceil, floor, not_null, to_array, to_string, type

A usage description is shown below the candidate list (toggle with Ctrl+X).

The matching JSON key is highlighted in yellow and the view auto-scrolls to it in two situations:

  • While typing — as soon as the query narrows down to a single candidate (e.g. typing .na when only name matches), the corresponding key is highlighted immediately, before pressing Tab.
  • While cycling with Tab / Shift+Tab — the key for each selected candidate is highlighted as you cycle through the list.

In both cases, if the key is outside the visible area the JSON view scrolls to bring it into view. Only the key at the correct nesting level is highlighted — nested keys with the same name are ignored.

When a function candidate is confirmed, the arguments are automatically filled in and the cursor is placed at the right position:

FunctionInserted asCursor position
containscontains(@, '')inside ''
ends_withends_with(@, '')inside ''
starts_withstarts_with(@, '')inside ''
joinjoin('', @)inside '' (separator)
sort_bysort_by(@, &field)on field placeholder
max_bymax_by(@, &field)on field placeholder
min_bymin_by(@, &field)on field placeholder
mapmap(&expr, @)on expr placeholder

Placeholder text is shown in cyan. Typing any character replaces the entire placeholder.

For functions that take a &field argument (sort_by, max_by, min_by, map), jid automatically shows the available field names from the base array as soon as the &field template is inserted:

.stats | sort_by(@, &field) → field names shown: base_stat effort stat
.stats | sort_by(@, &b → filtered: base_stat
.stats | sort_by(@, &base_stat) → confirmed; expression evaluates normally
  • Tab / Shift+Tab cycles through field candidates; cursor stays between & and )
  • Typing filters candidates by the partial name after &
  • Enter or Tab (when only one candidate) confirms the selection
  • Ctrl+W deletes the field name but keeps & (e.g. &base_stat)&)

After a wildcard expression like .game_indices[*], jid shows the field names of the array elements as candidates:

.game_indices[*] → candidates: game_index, version
.game_indices[*].<Tab> → same candidates (trailing dot still shows fields)
.game_indices[*].v<Tab> → filtered: version
.game_indices[*].version → shows array result; suggests [ for index navigation
.game_indices[*].version[0] → first version object; candidates: name, url

Ctrl+W removes one segment at a time from the end of a JMESPath expression:

.[3] | to_array(@)[0].id →(Ctrl+W)→ .[3] | to_array(@)[0]
.[3] | to_array(@)[0] →(Ctrl+W)→ .[3] | to_array(@)
.[3] | to_array(@) →(Ctrl+W)→ .[3] |
.[3] | →(Ctrl+W)→ .[3]

Inside a function call, the &field argument is treated as one unit and & is preserved:

.stats | max_by(@, &base_stat) →(Ctrl+W)→ .stats | max_by(@, &
.stats | max_by(@, & →(Ctrl+W)→ .stats |