JSONPath examples
One sample document, and the expressions people actually need against it, each with the result it produces.
Last reviewed
The sample document
Every expression on this page is evaluated against this one document, so you can read an expression and its result together rather than reconstructing the input each time.
{
"store": {
"name": "Northside Books",
"books": [
{ "title": "Dune", "author": "Herbert", "price": 12.5, "tags": ["scifi"] },
{ "title": "Neuromancer","author": "Gibson", "price": 9.99, "tags": ["scifi","cyber"] },
{ "title": "Ubik", "author": "Dick", "price": 21.0, "tags": ["scifi"] }
],
"manager": { "name": "Ada", "email": "[email protected]" }
}
}Basic navigation
Every expression starts at $, the root of the document. From there, dot notation walks into object keys and bracket notation does the same thing with an explicit string — which is the form you need when a key contains a space, a dot or a hyphen.
$ the whole document
$.store.name "Northside Books"
$.store.manager.email "[email protected]"
$.store.books[0].title "Dune"
$['store']['name'] same as $.store.name — bracket form, needed for keys with spaces or dotsArrays
An index selects one element; a wildcard selects all of them and returns a list. Slices use the same start:end convention as Python, with the end exclusive, and negative indexes counting back from the end — [-1:] is the idiomatic way to say "the last one".
The result of a wildcard or a slice is always a list, even when it contains exactly one element. Code that consumes a JSONPath result should expect a list and handle the single-match case, rather than assuming it gets a value back.
$.store.books[*].title ["Dune", "Neuromancer", "Ubik"]
$.store.books[0] the first book object
$.store.books[-1:] the last book — negative slice
$.store.books[0:2] the first two books
$.store.books[*].tags[0] ["scifi", "scifi", "scifi"]Recursive descent
The .. operator searches at any depth, which is what makes it useful for finding a field whose position you do not know — and expensive on large documents, because it visits every node.
$..title every "title" anywhere in the document
$..price [12.5, 9.99, 21.0]
$..[?(@.price)] every object that has a price keyFilters
A filter is written [?(…)] and is evaluated once per element, with @ bound to the element being tested. Only elements for which the expression is true come back.
Filter support varies more than anything else in JSONPath. There was no formal specification until RFC 9535 in 2024, so implementations differ on string quoting, on length, on regular-expression support and on whether && is allowed at all. Test an expression against the implementation you are going to run it in.
$.store.books[?(@.price < 15)] Dune and Neuromancer
$.store.books[?(@.author == 'Gibson')] Neuromancer
$.store.books[?(@.price > 10 && @.price < 20)] Dune
$.store.books[?(@.tags.length > 1)] NeuromancerPulling out a flat table
The most common real use is not fetching one value — it is reducing a nested response to the handful of fields you want, usually on the way to a CSV or a spreadsheet. A wildcard over the collection plus one expression per column does it.
$.store.books[*].title ["Dune", "Neuromancer", "Ubik"]
$.store.books[*].author ["Herbert", "Gibson", "Dick"]
$.store.books[*].price [12.5, 9.99, 21.0]
# the same three columns, as one object per row
$.store.books[*]['title','author','price']title,author,price
Dune,Herbert,12.5
Neuromancer,Gibson,9.99
Ubik,Dick,21.0Escaping and awkward keys
Dot notation only works for keys that look like identifiers. Anything else — a dot inside the key, a space, a hyphen, a digit at the start, or a key that is the empty string — has to use bracket notation with a quoted string.
$['user.name'] the key literally called "user.name"
$.user.name the "name" key inside the "user" object — different thing
$['first name'] a key containing a space
$['@type'] a key starting with a symbol
$[''] the empty-string key, which is legal JSONThings that catch people out
- A key containing a dot or a space must use bracket notation: $['first.name'].
- $..* returns every value in the document, which on a large payload is rarely what was intended.
- A query that matches nothing returns an empty list, not null — check length rather than truthiness.
- JSONPath reads; it does not write. Modifying a document needs a transform step, not a path expression.
- Recursive descent visits every node, so $..price on a hundred-megabyte document is a full traversal. Anchor the path when you know where the field lives.
- RFC 9535 standardised the syntax in 2024, but most deployed libraries predate it. Filters, the union syntax and script expressions are where implementations diverge — test before you rely on one.
Keep reading
- JSON Schema examples — Schemas that do something, from a five-line object check up to conditionals and reusable definitions.
- JSON API response examples — The response shapes you meet in practice, and what each convention costs the client that consumes it.