A native desktop tool for browsing and querying large JSON files β drag in a file (or paste JSON directly) and query it with jq, JSON Pointer, JSONPath, or JMESPath. A Tools window merges, formats, diffs, patches and validates documents too. Built in Rust with egui/eframe.
-
Four query dialects, one box β jq (via embedded jaq), JSON Pointer (RFC 6901), JSONPath (RFC 9535), and JMESPath. Pick one from the toolbar or let the app auto-detect it from what you type.
-
Inline autocomplete β as-you-type suggestions for each dialect's built-in functions (with a short doc string) and for the loaded document's own keys and array indices β type
.or[to see what's there, with a sample value next to each key. In jq it follows pipes and calls too: inside.[] | select(.it offers the fields of each record. Accepted text is spelled for the dialect (.["first name"]in jq,$["first name"]in JSONPath,."first name"in JMESPath). Off by default β switch it on with the π‘ button in the toolbar. -
Colour-coded queries β the query box tints each step of what you type (
.[],select(β¦),sort_by(β¦),.user.name; a Pointer's/segments) in the same palette the tutorial uses, leaving pipes, commas and operators plain, so a long query's structure is visible at a glance β see the query at the top of this page. A call inside a call gets its own tint, the colours follow the selected dialect, and half-typed queries are fine. -
Built-in tutorial β the π icon in the toolbar (or
F1) opens a separate window with a lesson tree for each dialect. Every lesson has short examples with the query broken down piece by piece and a live result; βΆ Try it loads an example's data and query into the main window so you can edit and experiment. See Tutorial. -
Tools β the π icon next to the tutorial opens the Tools window, with a tab for each of five utilities that go with the viewer: Merge JSON, Format JSON, Diff JSON, Patch JSON and Validate Schema. Each is shown in action under Tools below. They open in a window of their own, or docked in the main window β the β button in their row of tabs gives the main window a row of tabs: Json Query itself, then the five tools.
-
Streamed, cancellable queries β results appear as jq produces them, so
first(...)/limit(...)genuinely stop early; starting a new query aborts whatever was still running. -
Exact number round-tripping β big integers (snowflake IDs, Postgres bigints) survive a query byte-for-byte instead of quietly rounding through an
f64. -
NDJSON support β one JSON value per line loads as a single queryable document, no separate format to pick.
-
Tree or raw text views β toggle either the source document or the query results between a virtualized, expand/collapse tree and plain, selectable/copyable pretty-printed text.
-
CSV and TSV out β end a jq query with
@csvor@tsv, for example.[] | [.name, .age] | @csv, and the results are rows of text: Copy to Clipboard, Save⦠and the Text view write them as CSV or TSV, a line per result, not as quoted JSON strings. ACSV/TSVnote beside the Tree and Text buttons says when that applies. (jaq has neither filter; jsonquery adds them, withIN,INDEX,JOIN,tostream,fromstreamandtruncate_stream.) The tutorial teaches them on the pages of its Tables & lookups and Event streams topics. Below, the Text view of an@csvquery, and the file Save⦠wrote from it, open beside the window in a spreadsheet; end the query in@tsvand the rows are tab-separated. -
Search β
Ctrl+Fopens a Notepad++-style Find dialog with the cursor already in its field: a case-insensitive substring or regex search across the source or the results tree. Find (orEnter) jumps to each match in turn β expanded, scrolled to and highlighted β with a running "2 of 3", wrapping past the last one; Find All lists every match in a panel below, where a click reveals it. -
Find in Source β right-click a result row to see where it came from. The row's key and value are matched against the source, and for array elements their position: one hit is revealed directly, several are listed with the best guess selected, and a computed value falls back to a text search.
-
Right-click row menus β copy a node's path or its JSON to the clipboard, search from that scope, save just that node to a file, or expand a whole subtree at once.
-
Save to file β the whole source document, the whole result set, or a single node, independently.
-
Load however's convenient β drag-and-drop (several files at once are offered to Merge JSON), a Source field that takes a URL or a local path (type it or paste it, or browse with β¦), or pasting JSON straight into the text area.
-
Resizable query box that scrolls β drag the query panel's bottom edge to make it any height; a long query scrolls inside it (the cursor stays in view) instead of taking over the window.
-
Pop-out panes β the Query, Source and Results panes each have a small β¬ icon in the top right corner of their header that opens the pane in a window of its own β a big query on a second monitor, or the results beside a full-height source. The main window gives the room to whatever is left. The β¬ icon in that window, or just closing it, docks the pane back, and a π button in the toolbar (there while anything is out) brings every window back at once. The Source pane's window has a Source field of its own on top (with β¦, Load and Clear), so a document can be opened from there. Shortcuts and search work in each window.
-
Light and dark themes, switchable from the toolbar.
-
Settings and a memory β the β at the right end of the status bar opens a small window with the limit on file sizes that matters: from what size a file is memory-mapped and kept on disk instead of being loaded. Under Advanced are the others: how much the Tools window takes, how big a download or a copy may be, how much a query on a huge file may hold. Hover a name for what it does and its default, which is what the app has always used. The app also starts as you left it: the theme, whether autocomplete is on, the size of the window (maximized or not) and of its panes, and whether the Tools are docked. All of it is in one small file,
~/.jsonquery/settings.json. See docs/settings.md. -
On the web β the π in the status bar, between the β and the β, opens jsonquery.dev in your web browser: this app's query engine in a browser tab, with nothing to install β jq, JSONPath, JMESPath and JSON Pointer queries, the five tools, and short lessons for each language. The β window links to the site too. The app never contacts the site by itself: the π only hands the address to your browser when you click it.
-
Keyboard shortcuts β
Ctrl+Enterrun/apply,Ctrl+Fsearch,Ctrl+Ssave (both scoped to whichever panel you last clicked),F1tutorial.
The π icon in the toolbar opens the Tools window: five small utilities,
each on a tab of its own, laid out like the main window β a command row with
the tool's main button and its options, what goes in on the left, what came
out on the right, and a status bar that says what happened. JSON goes into a
box by pasting, by dropping a file on the window, with Open fileβ¦, or with
Open document (the one in the main window). A result can be copied, saved,
or opened in the main window as a document of its own, to query like any
other. Ctrl+Enter runs the tab's main button and Cancel stops a job. The
tools work in memory, so they are for documents that are not very large (what
a run is given may add up to 128 MB, which is a setting). Details in
docs/tools.md.
The Tools can also be docked into the main window, so that the whole app is one
window: the β button at the right end of their row of tabs gives the main window
a row of tabs β Json Query first, which is the window as it has always been (the
source field, the query, Source and Results), then one tab for each tool β and what
the tab in front holds takes the window. The theme and the tutorial stay at the right
end of the row; the π at the bottom right, in the status bar beside the β, undocks
the Tools into a window of their own again.
Ctrl+Enter and a file dropped on the window go to what is in front: a tool's tab runs
and takes the file in one of its boxes, Json Query runs the query and opens the file
as the document (several files go to Merge, whose tab comes to the front). Where the
Tools are is remembered.
Combines several files into one document with a jq filter, the way jq -s
does: the files are read in the order listed and slurped into one array, which
is the filter's input, and $files holds their names. Drop the files on the
window (or several at once on the main window), or press Add filesβ¦; pick a
ready-made filter from Merge as β append arrays, append sorted and
de-duplicated, deep-merge objects, bundle by file name β or edit it into your
own, and press Merge. The result can be saved, or opened in the main
window.
Deep-merge objects lays each file over the one before it, key by key all the
way down: a later file wins a clash between plain values, a key that only one file
has is kept, and an array is replaced as a whole. Below, a defaults.json, a
production.json and a local.json become one configuration. A filter of your
own can merge differently β docs/tools.md
has one that joins the arrays too.
Pretty-prints with 2 or 4 spaces or a tab, minifies, sorts the keys at every
depth, and can write everything outside ASCII as \uXXXX escapes. Numbers come
out exactly as they went in, however many digits they have.
Compares a Left and a Right document the way a file-comparison tool does.
Side by side shows both pretty-printed, line by line: what only Left has in
red, what only Right has in green, what changed in amber with the differing
characters picked out. The sides scroll together, the strip at the right edge
has a tick for every difference, β²/βΌ (Alt+Up, Alt+Down) step through them,
and Differences only folds what is the same. Its tab compares the two
documents by itself β Compare is for comparing again. Changes lists each
change with its JSON Pointer, and Patch is the RFC 6902 JSON Patch that turns
Left into Right β Copy patch or Save patchβ¦ it. Key order is not a
difference, numbers are compared by value with their exact digits, and arrays
are aligned by content, so an inserted element is one change rather than a
change to every element after it.
Each difference has two arrows between the sides, one over the other, at its first
line: press one and the document it points at takes what the other has there, as a
file-comparison tool's "copy to left/right" does; the comparison runs again and the
view stays where it was. Not the whole difference? Click a line to pick it
(Ctrl adds one, Shift picks a run, a drag runs over several, Esc lets go):
the arrows, β΄ and β΅ (Alt+Left, Alt+Right) and the right-click menu of a
line then move only the lines picked. Either side can also be edited in place:
double-click a line to put a caret in it β type, press Enter, and what you
typed (a value, a member, nothing to take the line out, several to put them in) is
in the document and compared again. A document that a move or an edit changed says
so, and the Saveβ¦ over its column writes it to a file β either, or both.
Applies an RFC 6902 JSON Patch (a list of operations) or an RFC 7386 JSON Merge Patch to a document. A patch is all or nothing, and an error names the operation that failed.
Checks a document against a JSON Schema (drafts 4, 6, 7, 2019-09 and 2020-12,
read from $schema) and lists every problem with its pointer and what is
wrong. For the document that is open in the main window, Show in main
window reveals a problem there. Nothing is ever fetched: a $ref has to
point inside the schema.
- Drag-and-drop doesn't work on native Wayland β a gap in
winit(eframe's windowing library), which only implements OS-level file drop on Windows, macOS, and X11 (rust-windowing/winit#1881). The Source field (and its ⦠file picker), the Tools window's Add files⦠and Open file⦠buttons and pasting all work fine everywhere. Workaround: run under XWayland instead, one click away once it is set up; see Dropping files on a Wayland desktop. - Pop-out windows open wherever the compositor puts them on native
Wayland β
winitcan neither set nor read a window's position there, so a popped-out pane can't open over the spot it left or reopen where you moved it. (Windows, macOS and X11 can; only X11 has been tried β the XWayland entry above gets you there on a Wayland desktop.) - A file of 256 MiB or more is not parsed but kept on disk and read as you look
at it (that size is a setting; memory-mapped, and indexed once when it opens; a
download and the result of a Merge that big are kept in a temporary file the same
way), so that a gigabyte of
JSON takes megabytes, not the twelve to seventeen times its size that a parsed
tree does. Long lists are shown in runs of a thousand; jq queries read the file
as they go, so
.[] | select(β¦) | .name,map(β¦),length,.[1234567],first(β¦),..,sort_by(β¦),group_by(β¦)andmin_by(β¦)work on any size (a sort takes some memory for the keys, about the size of the file at the most), but a program that needs the whole of a list as a value (addon the document,to_entries,flatten) says so instead of running. JSONPath and JMESPath work the same way ($[?(@.qty > 48)].id,[?qty > `48`].id), apart from functions that need a whole big list (sort_by,max). Format in the Tools window writes such a file indented or minified without holding it; the rest of the Tools window, and Copy of more than 64 MiB (a setting too), don't work on one, and the file should stay as it is while it is open (if another program cuts it short, the app says so and refuses to answer from what is gone, rather than closing). See Scaling beyond in-memory.
brew tap nujufas/jsonquery-gui
brew install jsonquery-guimacOS builds aren't published yet, so the tap is Linux-only for now. If
Homebrew refuses the formula as an untrusted tap, run
brew trust nujufas/jsonquery-gui first.
sudo snap install jsonquery-guiAlso available on the Snap Store, for
both x86-64 (amd64) and ARM (arm64) machines. The snap is sandboxed: it reads
files in your home folder directly. For files on an external drive or under
/mnt, run sudo snap connect jsonquery-gui:removable-media once (the β¦
file picker works for any file without it). To drop files on its window under
Wayland, see Dropping files on a Wayland desktop.
scoop bucket add jsonquery-gui https://github.com/nujufas/scoop-jsonquery-gui
scoop install jsonquery-gui/jsonquery-guiThis installs the release's Windows zip with a Start-menu shortcut and a
jsonquery-gui command; scoop update jsonquery-gui follows new releases. The
executable is not code-signed, so Windows SmartScreen may warn the first time
it runs.
Prebuilt Linux and Windows binaries are attached to each
GitHub Release. An AUR
package (jsonquery-gui-bin) is also available for Arch-based distros. To
build the app yourself, see Build from source below.
The AppImage is desktop-pinnable out of the box: it self-registers a
.desktop entry and icon on first launch (no appimaged/AppImageLauncher
required), so right-click β Pin works from the taskbar/dock immediately. It
embeds the static type 2 runtime (no libfuse2 needed to start it), carries
fallback copies of the xkbcommon libraries for systems that lack them, and
embeds update information, so AppImageUpdate (or a launcher built on it) can
fetch newer releases. On a Wayland desktop it also adds a jsonquery (X11)
entry, for dropping files on the window (see
Dropping files on a Wayland desktop).
Most current Linux desktops (Ubuntu, Fedora and others) run Wayland, where jsonquery can't take a file dropped on its window (see Known limitations). Everything else works. To be able to drop files, start jsonquery under X11 instead (XWayland, which the desktop provides on request). Which one you have:
echo $XDG_SESSION_TYPE # wayland: read on. x11: nothing to doWhat you need is a jsonquery (X11) entry in your application menu, next to the regular jsonquery: click that one, and drop files on its window.
- AppImage: nothing to do. On a Wayland desktop the AppImage adds that entry
by itself the first time you start it, and again if you move it or replace it
with a newer one. (AppImages made before this was added don't: use the script
below.) To get rid of it, delete
~/.local/share/applications/jsonquery-gui-x11.desktop; it stays gone until you move or replace the AppImage. - Everything else (the tar.gz, the snap, the Arch package, an older
AppImage):
scripts/jsonquery-x11.shadds the entry (and, if you ask, a shortcut on the Desktop) with one command. The tar.gz has the script inside. For the others, the program carries it: when it is running on native Wayland, a β appears at the bottom right, beside the β. Click it, then Download jsonquery-x11.sh, and choose where to save it; the popup then shows the command to run, with a Copy command button. Or download it yourself:
curl -fLO https://raw.githubusercontent.com/nujufas/jsonquery_gui/master/scripts/jsonquery-x11.sh
bash jsonquery-x11.sh # add "jsonquery (X11)" to the application menu
bash jsonquery-x11.sh --desktop # ... and put a shortcut on the Desktop tooThen press the Super key, type jsonquery, click jsonquery (X11), and drop
files on its window.
- The script finds jsonquery by itself: the program next to it, the snap, or
the Arch package. If you keep an AppImage somewhere, name it (make it
executable first with
chmod +x):bash jsonquery-x11.sh ~/Apps/jsonquery_gui-0.5.1-x86_64.AppImage - Moved or updated the program? Run the script again; it rewrites the entry.
bash jsonquery-x11.sh runstarts jsonquery under X11 once, without adding anything;removetakes the entry and the shortcut away;checksays what it found. On a desktop that is not Wayland the script does nothing.- With no script at all, the same thing from a terminal:
env -u WAYLAND_DISPLAY -u WAYLAND_SOCKET jsonquery_gui(for an AppImage, its file instead; the snap's program is/snap/bin/jsonquery-gui; from source,env -u WAYLAND_DISPLAY -u WAYLAND_SOCKET cargo run --release -p jsonquery_gui). - It needs XWayland. If the script says
DISPLAYis not set, your desktop has it switched off: look for an XWayland or "X11 apps" setting, then log in again.
Requires a Rust toolchain (stable).
git clone https://github.com/nujufas/jsonquery_gui.git
cd jsonquery_gui
cargo run --release -p jsonquery_gui- Get JSON in: drag a file onto the window, type or paste a URL or file path into the Source field and press Load (β¦ browses for a file), or paste JSON into the text area.
- Pick a query engine (or leave it on auto-detect) and write a query, e.g.
.users[] | select(.active) | {name, roles}for jq,/users/0for Pointer,$.users[*].namefor JSONPath, orusers[?active].namefor JMESPath. New to one of them? The π tutorial has short lessons for all four, and the π‘ autocomplete knows the document's keys. - Press Run (or
Ctrl+Enter). Results stream into the right-hand panel β toggle it between Tree and Text, search it, pop it out into its own window, or save it. - To merge, format, diff, patch or validate documents instead, open the π Tools window.
Native release build for the current platform:
cargo build --release -p jsonquery_gui
# binary at target/release/jsonquery_guicargo test --workspace # unit tests: parsing and tree logic, the query engines and tools, headless window tests
cargo clippy --workspace --all-targetsThe workspace is split into three crates so the non-GUI logic can be tested without pulling in a GUI toolkit:
crates/coreβ file ingest (parse, or mmap + index for a file of 256 MiB or more) and the virtualized-tree data layer.crates/queryβ the four query engines, dispatched through a sharedQueryEnginetrait, plus the merge, format, diff, patch and schema logic behind the Tools window.crates/appβ the eframe/egui application itself.
The end-to-end tests live in their own repository,
jsonquery_test: a
Robot Framework suite that starts the real
application on a virtual display of its own and drives it the way a person
would. Its README says what it covers and how to run it; clone it beside this
checkout (it finds the app as ../jsonquery_gui, or wherever JQ_APP_DIR
points) and start with ./run.sh.
The CI workflow (ci.yml) runs fmt, clippy, the
unit tests and a release build on Linux, Windows and macOS for every push and
pull request. The GUI suite runs on Linux from the Actions tab (Run
workflow, optionally just one suite) and every Monday; its report is kept as
the gui-test-results artifact.
The design β pipeline, concurrency model, crate layout β is written up in
docs/:
docs/index.mdβ problem statement, goals, high-level shape.docs/architecture.mdβ the full system design.docs/query-engines.mdβ the query-dialect landscape and why these four were picked.docs/tools.mdβ the Tools window, tool by tool.
MIT. The app has no accounts, telemetry, crash reporting or update checks of its own β see PRIVACY.md.
Built with the help of Claude β see
docs/ for the architecture docs behind it.












