About JSONPath Tester
JSONPath is a query language for JSON, modelled loosely on XPath. $ is the root, dots and brackets walk into properties and array elements, * matches everything at one level, .. searches recursively at any depth, and [?(...)] filters by a predicate.
The recursive descent operator is the one worth learning first, because it solves the common real problem: pulling every occurrence of a field out of a deeply nested response without knowing the path. $..id finds every id anywhere in the document, at any depth.
Filters are where most of the power is. $.items[?(@.price > 100)] selects array elements by a condition, with @ referring to the current element. They are also where implementations diverge most - the syntax for string matching, regular expressions and existence checks differs noticeably between libraries.
That divergence is the main practical caution. JSONPath was a blog post in 2007, not a specification, so libraries disagree about filter syntax, whether results are deduplicated, how a query returning nothing is represented, and whether the result is always an array. RFC 9535 finally standardised it in 2024, but most libraries in use predate it and do not fully conform. An expression that works in one tool may fail or return something different in another.
Queries run in your browser and nothing is transmitted.
How to use the JSONPath Tester
- Paste the JSON document, then enter a JSONPath expression.
- Start with $ and build up one segment at a time - it is much easier to see where a path stops matching than to debug a long one.
- Use $.. to find a field at unknown depth, and [?(@.field == value)] to filter.
- Before relying on an expression elsewhere, test it in the library you will actually use - implementations differ.
Examples
-
Path
$.users[0].name
JSONPath Tester in code
The same operation this tool performs, in the languages you are most likely to need it.
$ // the root
$.store.book[0].title // a specific path
$.store.book[*].author // every author
$..author // every author at any depth
$..book[2] // the third book, wherever books appear
$..book[-1] // the last book
$..book[0,1] // the first two
$..book[:2] // slice - first two
$..book[?(@.isbn)] // elements that HAVE an isbn
$..book[?(@.price < 10)] // filter by value
$..* // absolutely everything
$..book.length // count (support varies by library)
import { JSONPath } from "jsonpath-plus";
JSONPath({ path: "$..book[?(@.price < 10)]", json: data });
// resultType: "path" tells you WHERE each match came from,
// which is what you want when reporting an error location
JSONPath({ path: "$..id", json: data, resultType: "path" });
// Results are always an array - an empty array means no match,
// which is different from a match whose value is null.
const found = JSONPath({ path: "$.missing", json: data });
found.length === 0; // no match
// vs a real null value, which yields [null]
# jq has its own syntax, is far more capable, and unlike
# JSONPath is consistently implemented (there is one jq).
jq '.store.book[0].title' data.json
jq '.store.book[].author' data.json
jq '.. | .author? // empty' data.json # recursive descent
jq '.store.book[] | select(.price < 10)' data.json
# kubectl and some other tools speak JSONPath natively
kubectl get pods -o jsonpath='{.items[*].metadata.name}'
When you need this
- Pulling one field out of a large nested API response.
- Finding every occurrence of a field regardless of where it sits.
- Building a kubectl -o jsonpath expression and checking it before using it.
- Filtering an array by a condition to see which elements match.
Common problems and what causes them
- Implementations disagree
- JSONPath was never specified until RFC 9535 in 2024, and most libraries predate it. Filter syntax, regular expression support, deduplication and the shape of an empty result all vary. Test in the library you will actually deploy with.
- No match versus a null value
- A query matching nothing usually returns an empty array, while a query matching a field whose value is null returns [null]. Code that treats both as falsy conflates 'absent' with 'explicitly null'.
- Filter expressions evaluated unsafely
- Some older JavaScript implementations evaluated filter expressions with eval, making a user-supplied JSONPath a code execution risk. Never accept a JSONPath from an untrusted source without checking how your library evaluates filters.
- Recursive descent being expensive
- $.. walks the entire document. On a large payload, inside a loop, that is a real performance cost. Use an explicit path when you know it.
- Quoting keys with special characters
- A key containing a dot, a space or a hyphen cannot be reached with dot notation. Use bracket notation with quotes: $['user.name'] rather than $.user.name, which would look for a nested object.
- Assuming order is preserved
- Results from a recursive descent or a wildcard come back in implementation-defined order. Do not rely on it if the order carries meaning.
FAQ
- What is the difference between JSONPath and jq?
- JSONPath is a path expression language with several inconsistent implementations; jq is a full transformation language with one canonical implementation. JSONPath appears in tools like kubectl and various test frameworks; jq is better for anything involving transformation rather than selection.
- How do I find a field at an unknown depth?
- Recursive descent: $..fieldName returns every occurrence anywhere in the document. It is the operator that solves most real JSONPath problems, at the cost of walking the whole tree.
- Why does the same expression behave differently in another tool?
- Because JSONPath had no specification until RFC 9535 in 2024 and most libraries were written against a 2007 blog post. Filter syntax and result semantics genuinely differ between implementations.
- How do I query a key containing a dot?
- Bracket notation with quotes: $['user.name']. Dot notation would interpret it as a nested path into an object called user.
Related reading
- JSON formatter inspect the shape first