JSONPath Query Tester

Run JSONPath queries against a JSON document and see every match instantly, with the syntax reference and the implementation differences that cause surprises.

Syntax supported

$.name · $['name'] · $[0] · $[-1] · $[0:2] · $.* · $..name · $[?(@.key == value)] · > < >= <= != and bare @.key for existence

A value can be neither greater than five, nor less than five, nor equal to five

All three at once, in the same filter, on the same record. Take {"n": "5"} — a five stored as text, which is what arrives from a CSV import or a form field:

FilterMatchesWhy
?(@.n == 5) no strict: a string is not a number
?(@.n >= 5) yes coerced: the text becomes 5
?(@.n <= 5) yes coerced: the text becomes 5
?(@.n > 5) no coerced, and 5 is not more or less than 5
?(@.n < 5) no coerced, and 5 is not more or less than 5

Every one of those answers is correct, and the three of them cannot all be correct about the data. The reason is that the operators are not one family: == is strict and never converts anything, while >, <, >= and <= convert text to a number whenever they can.

Filter over 1, "1", 2, "2"Kept
?(@.n == 1)1
?(@.n == '1')"1"
?(@.n > 0)1, "1", 2, "2"
?(@.n >= 1)1, "1", 2, "2"
?(@.n < 2)1, "1"

Worth knowing in one direction particularly. If a filter for == 5 comes back empty on data you can see contains fives, the fives are strings. Switching to >= 5 will appear to fix it and will quietly also match 6, 7 and "50". The real fix is upstream.

"Not equal to 1" includes every record with no such field

A record missing the key yields nothing at all, and nothing-at-all is genuinely not equal to 1. Over the two records {"a": 1} and {"b": 2}:

FilterMatchesThe record without a
?(@.a == 1) 1 excluded
?(@.a != 1) 1 included
?(@.a > 0) 1 excluded
?(@.a < 99) 1 excluded

So filtering for absence and filtering for a different value are the same query here, and they are usually different questions. The comparison operators are consistent about it — a missing value is never greater or less than anything, so all four exclude it. Inequality is the odd one out.

And a bare field test asks whether it exists, not whether it is set to something cheerful

A filter with no operator keeps anything where the field is present. That is not a truthiness test, even though it reads like one — null, false and 0 all count as present.

Record?(@.a)Truthiness would say
{"a": 1} kept kept
{"a": null} kept dropped
{"a": undefined} dropped dropped
{"b": 2} dropped dropped
{"a": false} kept dropped
{"a": 0} kept dropped

4 of the 6 records have the field; truthiness would have kept 1. The existence reading is almost certainly the one you want from a path query, and it is worth having read once that it is the one you get. A field written as an explicit nothing is treated the same as a field that was never there.

How to use

  1. Paste your JSON document.
  2. Enter a JSONPath expression.
  3. Read the matches and their paths.
  4. Build the query up gradually rather than all at once.

Frequently asked questions

What is JSONPath?

A query language for JSON, loosely modelled on XPath for XML. It lets you select values by path, filter arrays by condition, and search recursively at any depth, which is far more concise than walking the structure by hand.

What does the dollar sign mean?

The root of the document. Every expression starts there, so a path reads as a route from the top down. Some implementations also support an at-sign for the current node inside a filter expression.

What does the double dot do?

Searches recursively at any depth, so it finds a named key wherever it occurs rather than only at one level. It is the most useful operator in the language and also the slowest, since it has to visit every node.

How do filters work?

A filter expression in square brackets selects array elements meeting a condition — a price below a threshold, or a field existing at all. The comparison syntax varies noticeably between implementations, which is where most portability problems arise.

Is JSONPath standardised?

Only recently, and inconsistently applied. The original was a 2007 blog post rather than a specification, so implementations diverged over filters, string handling and edge cases. RFC 9535 standardised it in 2024, but many libraries still follow their own older behaviour.

When should I use this rather than writing code?

For exploration and for configuration. It is excellent for finding your way around an unfamiliar document, and for cases where the path itself needs to be configurable rather than hard-coded. For fixed access in application code, plain property access is clearer and faster.

🔒 This tool runs entirely in your browser. Nothing you enter is uploaded, logged, or stored.