JSON Query Tester (JSONPath & jq)

Run a JSONPath (RFC 9535) query or a jq filter against pasted JSON. Every match is listed with its exact path and highlighted in a tree, and Show Work counts the nodes after each step.

Tester Web & Dev Updated Oct 4, 2026
Learn how this works
How to Use
  1. Choose the language: JSONPath (queries start with $) or jq (filters start with .).
  2. Paste JSON into the document box or drop a .json file of up to 10 MB. The bookstore sample is loaded to start with.
  3. Type a query such as $..book[[email protected] < 10].title or .store.book[] | select(.price < 10) | .title. Results update as you type.
  4. Read the results: each one shows its path, such as $['store']['book'][0]['title'], and its value. Matches are highlighted in the tree; click a result to jump to it.
  5. Open Show Work to see the query split into tokens and the number of nodes left after each segment or pipeline stage.
  6. Press Copy results to copy the values as a JSON array, or try a preset.
Input
runs as you type
paste or drop a file
$..
Or drop a .json file (up to 10 MB)
Presets (bookstore)
Results
Waiting for a query
Document tree · matches highlighted
Matches
—
Language
JSONPath
Steps
—
Time
—

Worked Example

The bookstore document holds 4 books under store.book and a bicycle under store.bicycle: 28 values in all, 4 levels deep. Find the titles of the books that cost less than 10.

JSONPath: $..book[[email protected] < 10].title runs in three segments.
..book searches the root and its 8 containers for a member called book: 1 node, the array.
[[email protected] < 10] tests each of its 4 children: 8.95 < 10 yes, 12.99 no, 8.99 yes, 22.99 no, so 2 nodes remain.
.title takes the title of each: “Sayings of the Century” at $['store']['book'][0]['title'] and “Moby Dick” at $['store']['book'][2]['title'].

jq: .store.book[] | select(.price < 10) | .title is a three-stage pipeline. Stage 1 turns 1 input into 4 outputs (one per book), select keeps 2 of them, and stage 3 returns the same 2 titles, at .store.book[0].title and .store.book[2].title.

The common mistake: summing $..price to get the value of the books. .. searches everything, so it returns 5 prices, including the bicycle’s 19.95, and the total comes out as 73.87 instead of 53.92. Use $.store.book[*].price for the 4 book prices. The jq version of the same slip is pasting JSONPath filter syntax into jq: .store.book[?(@.price < 10)] is not jq; write .store.book[] | select(.price < 10).

Show Work

Type a query to see it tokenised and run step by step, with the number of nodes after each step.

JSONPath and jq Syntax

JSONPath: root and children
$  .name  ['name']  .*  [*]
Names with spaces or hyphens need brackets: $['first-name']
JSONPath: descendants
..name  ..*  ..[0]
Searches the node and everything below it, each node before its children
JSONPath: index, slice, union
[0]  [-1]  [start:end:step]  [0,2]  ['a','b']
End is excluded; [::-1] reverses; step 0 selects nothing
JSONPath: filters
[[email protected] < 10]  [[email protected]]  [[email protected]]  [?(@.a == 1 && @.b)]
@ is the item being tested, $ the root; == != < <= > >= || && !
JSONPath: functions
length()  count()  match()  search()  value()
match() must match the whole string; search() any part of it
Normalized path
$['store']['book'][0]['title']
One unique path per node: names in single quotes, indexes as numbers
jq: paths and pipes
.  .a.b  .[0]  .[]  .[2:4]  ..  .a?  |  ,
Each output of the left side becomes the input of the right side
jq: building values
[ .[] | .a ]  {title, price}  {n: .a, (.k): .v}
{title} is short for {title: .title}; put operators in brackets: {t: (.a + .b)}
jq: choosing
select(f)  if c then a elif d then b else e end  a // b
Only false and null count as false; a // b gives b when a has no other value
jq: sort order
null < false < true < numbers < strings < arrays < objects
Used by sort, sort_by, group_by, unique, min, max and comparisons

From a 2007 Blog Post to RFC 9535

JSONPath began as an article. In February 2007 Stefan Gössner published “JSONPath – XPath for JSON”, borrowing XPath’s idea of addressing parts of an XML document and using the same bookstore example this page loads. The article described the syntax by example and left many details open, so many libraries filled the gaps differently: whether a filter needs parentheses, how slices with negative steps behave, whether [(@.length-1)] runs script code.

The IETF JSONPath working group turned it into a standard. RFC 9535, “JSONPath: Query Expressions for JSON”, was published in February 2024, edited by Stefan Gössner, Glyn Normington and Carsten Bormann. It fixes the grammar, defines normalized paths, drops script expressions in favour of five functions, and uses I-Regexp (RFC 9485) for match() and search(), so a regular expression means the same thing in every implementation.

jq took a different route. Stephen Dolan released it in 2012 as a command-line processor, written in C, that treats every expression as a filter from one stream of JSON values to another; that is why it can sort, group and build new objects, not only select. Version 1.7 arrived in 2023, five years after 1.6. jq has no formal standard; this tester follows the jq manual for the subset it supports.

About This Tool

This tool runs JSONPath queries as defined by RFC 9535 and a documented subset of jq against JSON you paste or drop. Each result shows its normalized path and its value, the matches are highlighted in a collapsible tree, and Show Work lists the query’s tokens and how many nodes survive each segment or pipeline stage, which is usually where a query that returns nothing goes wrong.

It parses JSON with its own parser rather than the browser’s, so numbers are shown exactly as written, keys such as __proto__ are kept, and an error gives the line and column. Unsupported jq features produce an error that names them instead of a silently different answer. Everything runs in your browser under a step budget; nothing you paste is uploaded.

Related tools: JSON Formatter, JSON ⇄ CSV Converter, and YAML ↔ JSON Converter.

Frequently Asked Questions

What is the difference between JSONPath and jq?

JSONPath selects parts of a document: every result is a node that already exists, with a path such as $['store']['book'][2]. jq is a small programming language whose filters can also build new JSON, sort, group and do arithmetic. $..book[[email protected] < 10].title and .store.book[] | select(.price < 10) | .title both return Sayings of the Century and Moby Dick, but only jq can turn the books into [{"category":"fiction","count":3},{"category":"reference","count":1}].

Which parts of jq does this tester support?

A documented subset. Paths: ., .a.b, ."a b", .["a"], .[n] (negative counts from the end), .[], .[a:b], .. and the ? suffix. Operators: |, ,, //, and, or, comparisons and + - * / %. Construction: […] and {a, b: .x, "c": …, (k): …}, plus if … then … elif … else … end. Builtins: select, map, keys, keys_unsorted, length, has, sort, sort_by, group_by, unique, unique_by, min, max, min_by, max_by, add, any, all, first, last, reverse, type, to_entries, from_entries, values, empty, not, tostring, tonumber, tojson, join, split, ascii_downcase, ascii_upcase, startswith, endswith, floor, ceil, range and recurse. Not supported: $variables and as, reduce, foreach, def, try/catch, string interpolation \(…), @formats such as @csv, assignment operators such as |=, regex functions such as test, and path functions such as paths and getpath. Unsupported names give an error rather than a wrong answer.

Why does $..price return 5 prices instead of 4?

.. searches the whole document, and the bicycle has a price too. In the bookstore, $..price returns 8.95, 12.99, 8.99, 22.99 and 19.95, which add up to 73.87; $.store.book[*].price returns only the 4 book prices, which add up to 53.92. Use .. when you do not know the depth, and an explicit path when you only want one branch.

How do JSONPath filters treat missing members and mixed types?

RFC 9535 compares values, not text. A missing member is “nothing”: @.a == @.b is true when both are missing and false when only one is. <, <=, > and >= only compare two numbers or two strings; comparing a number with a string is simply false, not an error. [email protected] without a comparison tests that the member exists, so it matches 2 of the 4 books, even if the value were null or false.

How large a document can it query, and is anything uploaded?

Up to 10 MB of JSON. In our tests a 5.7 MB array of 100,000 objects parsed in about 0.1 s and a filter over all of it ran in about 0.05 s. Each query has a budget of 2,000,000 steps, so a runaway query such as [range(1e9)] stops with a message instead of freezing the tab, and the first 1,000 results are listed. Nothing is uploaded: parsing and querying run in your browser, and numbers are shown exactly as written, so 9007199254740993 is not rounded.

How do I use the JSON Query Tester (JSONPath & jq)?

Just type your numbers. The answer shows up right away — there is no button to press. Change anything and it updates by itself.

Does it cost anything or need an account?

No. The tool is completely free, there is no account to create, and it keeps working offline after the page first loads.

Is anything I type uploaded?

No. The tool works entirely on your device, so the values you enter never leave your browser.

Common Use Cases

Checking a filter before shipping it

Try $..book[[email protected] == "fiction" && @.price < 20].title on sample data first: it returns Sword of Honour and Moby Dick, and Show Work shows 4 books tested and 2 kept.

Debugging a jq one-liner

A shell script prints nothing? Paste the API response and the filter: the stage counts show where the outputs drop to 0, and errors such as Cannot index string with "x" name the cause.

Finding records missing a field

$..book[[email protected]].title lists the 2 books without an ISBN, Sayings of the Century and Sword of Honour, with their exact paths.

Grouping and counting

.store.book | group_by(.category) | map({category: .[0].category, count: length}) gives fiction 3 and reference 1.

Comparing against another value

$..book[[email protected] > $.store.bicycle.price].title compares each book with the bicycle’s 19.95 and returns only The Lord of the Rings at 22.99.

Moving to RFC 9535

Old JSONPath libraries accepted script expressions such as [(@.length-1)]. This tester explains the standard form, [-1], so queries behave the same in every compliant library.

Last updated: