JSONPath Explained: Query Your JSON
JSONPath syntax — root, child, recursive descent, slices, filters — with real queries against a sample document. Plus jq and JMESPath comparison.
JSONPath is to JSON what XPath is to XML: a small expression language for
picking values out of a document. It's standardized in RFC 9535 (2024)
and supported by every JSON tool worth using. If you've ever wanted to
say "give me every order with status: shipped and a total above $100",
JSONPath is the shortest path.
What JSONPath is
A JSONPath expression is a string that describes a set of locations in a JSON document. The evaluator walks the document and returns either the matching values, the matching paths, or both. The grammar is small enough to memorise — root, child, descent, index, slice, filter.
Throughout this guide we'll query this sample document:
{
"store": {
"books": [
{ "title": "Pragmatic Programmer", "price": 30, "tags": ["dev"] },
{ "title": "Designing Data-Intensive Apps", "price": 45, "tags": ["dev", "data"] },
{ "title": "The Art of Travel", "price": 12, "tags": ["essays"] }
],
"bicycle": { "color": "red", "price": 199 }
}
}
Root, child, recursive descent
Three operators do most of the work:
$— the root of the document..nameor["name"]— child access. Both forms are equivalent; the bracket form lets you use names with special characters...name— recursive descent. Matchesnameat any depth.
| Expression | Result |
|---|---|
$ | the whole document |
$.store.bicycle | { "color": "red", "price": 199 } |
$["store"]["bicycle"] | same as above |
$..price | [30, 45, 12, 199] — every price in the document |
$.store..title | ["Pragmatic Programmer", "Designing Data-Intensive Apps", "The Art of Travel"] |
Recursive descent is the single most useful operator. When you don't know
the exact path, $..fieldname finds every occurrence.
Array indices, slices, and wildcards
Arrays use bracket notation:
[0],[-1]— by index (negative counts from the end).[0, 2]— multiple indices.[1:3]— slice (Python-style, half-open).[*]— wildcard, every element.
| Expression | Result |
|---|---|
$.store.books[0] | the first book object |
$.store.books[-1].title | "The Art of Travel" |
$.store.books[0:2] | the first two books |
$.store.books[*].title | all three titles |
$.store.books[*].tags[*] | ["dev", "dev", "data", "essays"] |
The wildcard * also works on objects: $.store.* returns every value
under store (here, the books array and the bicycle object).
Filter expressions
Filters are predicates over array elements. The syntax is
[?expression], where @ refers to the current element.
| Expression | Result |
|---|---|
$.store.books[?(@.price < 20)] | [{ "title": "The Art of Travel", ... }] |
$.store.books[?(@.price >= 30)].title | first two titles |
$.store.books[?(@.tags.contains("data"))].title | ["Designing Data-Intensive Apps"] (implementation-dependent) |
$..[?(@.color == "red")] | [{ "color": "red", "price": 199 }] |
Supported operators in filters: comparison (==, !=, <, <=, >, >=),
boolean (&&, ||, !), and existence (just @.name — truthy if the
key exists). Some implementations add regex (=~) and string functions
(contains, match, length); these are non-standard so check your
library.
Common recipes
- Find a record by id —
$.users[?(@.id == "user_123")]. - Pull a field from every record —
$.users[*].email. - Find every
erroranywhere —$..error. - First N items —
$.items[:10]. - Last item —
$.items[-1]. - All keys at the top level —
$.*(object) or$[*](array).
For exploratory work, the JSON Viewer lets you click into a node and copy the JSONPath that reaches it — much faster than typing expressions blind.
JSONPath vs jq vs JMESPath
Three query languages cover overlapping ground:
- JSONPath — XPath-like, standardized in RFC 9535. Best for finding values. Limited transformation.
jq— a full Turing-complete language. Best for transforming JSON in shell pipelines. Filters, map/reduce, string operations, arithmetic. Mandatory CLI tool.- JMESPath — AWS's query language, used by every AWS CLI command
(
--query). Similar power to JSONPath plus projections and multi-select.
Rule of thumb: JSONPath in your code, jq in your shell, JMESPath if
you're already in the AWS ecosystem.
Try it
Open the JSON Viewer, paste a payload, and click any node — the tool copies the JSONPath that reaches it. For ad hoc filtering, type an expression in the search box.
Next steps
- Working with large JSON files — JSONPath shines on big documents where you'd never load everything.
- Comparing two JSON files — point a diff at the result of a JSONPath query to focus on one subtree.