Posted in Blog · Reading time ~7 min
JSONPath syntax: a practical cheat sheet
JSONPath is the "XPath for JSON" — a tiny query language for fishing values out of a JSON document. There are several dialects floating around (the original Goessner version, the new IETF RFC 9535, library-specific extensions); this cheat sheet sticks to the parts that work the same everywhere, with one example for each operator.
You can try every expression below in our JSONPath Tester — it accepts the same sample. If you need to validate the underlying JSON first, the JSON Validator reports the exact line and column of any error.
The sample
{
"store": {
"book": [
{ "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "price": 8.99 },
{ "category": "fiction", "author": "J.R.R. Tolkien", "title": "The Lord of the Rings", "price": 22.99 },
{ "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 }
],
"bicycle": { "color": "red", "price": 19.95 }
}
}
The root
$ — the whole document. Every JSONPath expression starts here.
Child by name
$.store or equivalently $['store'] — the value of the store key. Use bracket form when the key has special characters.
$.store.bicycle.color → "red"
Array index
$.store.book[0] — the first book. Negative indices count from the end: [-1] is the last element.
Wildcard
$.store.book[*] — every book. Works on objects too: $.store[*] yields the book array plus the bicycle object.
Union
Multiple indices: $.store.book[0, 2] — first and third books.
Multiple keys: $.store['book', 'bicycle'].
Slice
Python-style slicing on arrays.
$.store.book[0:2]— first two books.$.store.book[1:]— every book except the first.$.store.book[:2]— first two.$.store.book[::2]— every other.$.store.book[::-1]— reverse (not supported by every implementation).
Recursive descent
The killer feature: .. walks every descendant. $..price finds every price anywhere in the document — in this sample, four numbers.
Combine with anything else: $..book[0] for the first book in every nested book array, $..* for literally every value.
Filters
Inside brackets, ?(...) is a predicate, and @ refers to the current item.
$.store.book[?(@.price < 10)]— books cheaper than 10.$.store.book[?(@.category == 'fiction')]— only fiction.$.store.book[?(@.price > 8 && @.price < 20)]— combine with&&and||.$.store.book[?(@.title)]— books that have atitle(truthy filter).
Filter syntax is where dialects diverge most. The reasonable subset above works in jsonpath-plus, jq's path expressions (with translation), and JSONYard's own tester.
Common patterns
"Every value of a key, anywhere in the tree"
$..keyName
"All items in an array that match a condition"
$.path.to.array[?(@.field == 'value')]
"The first N items"
$.path.to.array[:N]
"All leaf values"
Hard in pure JSONPath; consider jq with .. | scalars.
What JSONPath can't do well
JSONPath is a value extractor, not a transformer. It can find things, but it can't reshape them. When you need to rename keys, compute derived values, group, or aggregate, reach for jq or JMESPath. They're more powerful and better-specified — JSONPath is great for the 80% of "give me the values at this shape".
The RFC 9535 footnote
IETF RFC 9535 (Feb 2024) finally standardized JSONPath. Most existing libraries don't match it perfectly yet. If you care about portability, stick to the operators above — they're the intersection of every common implementation. If you're starting fresh, look at the spec; the filter syntax in particular is cleaner than Goessner's.
One thing to remember
JSONPath is best when the path is hard-coded and you want to extract values from many similar documents. When the path itself is dynamic (computed from inputs), prefer iterating the JS structure directly — readable code beats clever query strings.
Try every example in the JSONPath Tester.