JSONPath Explained: Query JSON Like a Pro

When a JSON document is large, scrolling to find the value you need is tedious. JSONPath solves that: it is a small query language, invented by Stefan Goessner as an analogue of XPath for XML, that lets you describe a path to exactly the data you want and pull out every match at once.
The root and dot notation
Every JSONPath expression begins with $, which represents the root of the document. From there you walk into the structure with dots: $.store steps into the "store" property, and $.store.name reaches the name inside it. This mirrors how you would access the same data in JavaScript, so it feels familiar immediately. If any step in the path does not exist, the query simply returns no matches rather than throwing an error.
Dot notation only works for keys that look like identifiers. When a key contains a space, a dash, or a dot of its own, switch to bracket notation with quotes: $['first name'] or $['user.id']. The two styles mix freely inside one expression — $.orders[0]['line items'] is perfectly valid — and bracket notation is the safer default whenever you are pasting field names straight out of an API response.
Array indexes and wildcards
To reach into an array, use square brackets with an index: $.books[0] selects the first book, and negative indexes like $.books[-1] count from the end. The real power comes from the wildcard. Writing $.books[*] selects every element of the array, and $.books[*].title collects the title of each one in a single result list. The same wildcard works on objects to gather all their values.
This is where JSONPath saves the most time. Instead of a loop in code, one expression like $.users[*].email extracts a flat list of every email address in a collection — ideal for spot-checking an API response.
Recursive descent
The most powerful operator is the double dot, .., which searches recursively at any depth. The expression $..price finds every price field anywhere in the document, no matter how deeply it is nested or which parent it belongs to. This is invaluable when you know the field name but not its exact location — a common situation with deeply nested API payloads or configuration trees.
Recursive descent is also the operator most likely to surprise you on a big document, because it visits every node. On a deeply nested payload it can return far more matches than you expected — a $..id on an order may pick up customer, product and shipping identifiers all at once. Narrowing it with a parent step, as in $..lineItems[*].id, keeps the result set honest.
Combine the pieces and you can express precise queries: $..books[*].author gathers every author from every books array in the tree. Open the JSONPath tab, paste a document and experiment — the result updates the moment you run the expression.
Filters and slices
Beyond fixed indexes, JSONPath can select by value. A filter expression uses ?() with @ standing for the element currently being tested: $.books[?(@.price < 10)] returns only the cheap books, and $.users[?(@.active == true)].email collects the addresses of active users. Comparisons, logical and/or, and a bare existence test — $.books[?(@.isbn)] for books that have an ISBN at all — cover most real filtering needs without writing a line of code.
Slices borrow Python's syntax. $.books[0:3] takes the first three elements, $.books[-2:] the last two, and $.books[::2] every second one. A union selects several named children at once: $.book['title','author']. These operators compose, so $..items[?(@.qty > 0)].sku will walk the whole tree, keep only the in-stock lines and return a flat list of SKUs.
Dialects, the standard and where JSONPath fits
JSONPath grew out of a 2007 blog post rather than a committee, so implementations drifted apart: libraries disagreed on negative indexes, on what a filter may contain, and on whether results carry their paths back with them. RFC 9535, published in 2024, finally pinned the syntax down — the root identifier, descendant segments, name and index selectors, slices and filters — and most maintained libraries now track it. When a query behaves differently in two tools, a dialect difference is the usual explanation.
JSONPath is a selection language, not a transformation one. It finds values; it will not reshape them, compute totals or rename keys — that is what jq and similar tools are for. The narrow scope is a strength in the places JSONPath is embedded: assertions in API tests, field extraction in log pipelines, and mapping rules in integration platforms, where a single short expression is far easier to review than a script.
The takeaway
Start at $, walk with dots, index arrays with brackets, gather many values with [*], and search any depth with ... Try these expressions live in the JSONPath tab.
Open the tool and try it now
More guides

What Is JSON? A Plain-Language Introduction
JSON moves data across almost every API and config file. What it is, the six value types it supports, and the rules that keep a document valid.

JSON vs XML vs YAML: Which One and When
Three formats carry most of the world's structured data. Here's how JSON, XML and YAML differ in verbosity, features and the jobs each is best at.

Common JSON Syntax Errors and How to Fix Them
Most JSON failures come from the same few mistakes. Spot trailing commas, wrong quotes and unescaped characters — and learn to read the parser's message.