JSONPath is a query language for JSON, in the same spirit as XPath for XML. A short expression picks values out of a large document: every email address, the third item of a list, all records where a field is greater than 100. It is used in Postman tests, Kubernetes, API gateways, log tools and many libraries.
You can try every example below in the JSONPath Tester, which shows live matches and the path of each result.
Sample data
The examples use this document:
{
"store": {
"name": "Corner Books",
"books": [
{ "title": "Dune", "author": "Herbert", "price": 9.5, "tags": ["sf", "classic"] },
{ "title": "Emma", "author": "Austen", "price": 7.0, "tags": ["classic"] },
{ "title": "Neuromancer", "author": "Gibson", "price": 12.0, "tags": ["sf"] }
],
"open": true
}
}
The basics
| Expression | Meaning | Result on sample |
|---|---|---|
$ |
The root of the document | Everything |
$.store.name |
Child by dot notation | "Corner Books" |
$['store']['name'] |
Child by bracket notation | "Corner Books" |
$.store.books[0] |
Array item by index | The first book |
$.store.books[-1] |
Last item | Neuromancer |
$.store.books[0,2] |
Several indexes | First and third books |
$.store.books[0:2] |
Slice, start included, end excluded | First two books |
$.store.books[*] |
Wildcard: all items | All three books |
$.store.books[*].title |
A field from every item | Dune, Emma, Neuromancer |
$..price |
Recursive descent: anywhere in the tree | 9.5, 7.0, 12.0 |
$..author |
Same, for author |
Herbert, Austen, Gibson |
$ always starts the path. Dot notation is shorter, but use brackets with quotes when a key contains spaces, dashes or dots, for example $['first-name'].
Filters
A filter keeps only the items for which an expression is true. It looks like [?(...)], and inside it @ means “the current item”.
| Expression | Meaning |
|---|---|
$.store.books[?(@.price < 10)] |
Books cheaper than 10 |
$.store.books[?(@.author == 'Austen')] |
Books by Austen |
$.store.books[?(@.tags)] |
Books that have a tags field |
$.store.books[?(@.price > 8 && @.price < 12)] |
Combine with && |
$.store.books[?(@.price < 8 || @.author == 'Gibson')] |
Combine with || |
$.store.books[?(@.title.match(/^N/))] |
Regular-expression match (library-specific) |
$.store.books[?(@.price < 10)].title |
Filter, then take a field |
Comparison operators are ==, !=, <, <=, >, >=. Strings use single or double quotes.
Common tasks
Get every ID in a response, wherever it is:
$..id
Count-style checks. JSONPath returns matches; count them in your tool or script. In Postman:
const jp = require("jsonpath-plus").JSONPath;
const ids = jp({ path: "$.data[*].id", json: pm.response.json() });
pm.expect(ids.length).to.be.above(0);
Find failures in a list of results:
$.results[?(@.status != 'ok')]
Pick a nested field from each record:
$.users[*].address.city
Collect the last element of every array of tags:
$..tags[-1]
Records missing a field. Standard JSONPath cannot easily say “does not exist”. Use a filter on a different property, or check for the field with ?(!@.email), which many libraries support.
Differences between implementations
JSONPath was informally defined in 2007 and only standardised as RFC 9535 in 2024, so older libraries differ in the details:
- Filter syntax. Most accept
[?(@.x > 1)]. RFC 9535 also allows[?@.x > 1]without the parentheses. - Script expressions. Some libraries, including the popular
jsonpath-plus, allow JavaScript inside filters, such as@.price * 2 > 20. Others, like Kubernetes’ JSONPath, support only a subset. - Return values. Some tools return values, others return paths, others both. The tester shows both.
- Missing keys. Some libraries return an empty list, others raise an error.
- Negative indexes, slices, and
length. Support varies; test in your target tool.
When something works in the tester but not in your application, check which library the application uses and read its documentation.
JSONPath versus jq
jq is a full command-line language for transforming JSON: it can compute, reshape and aggregate. JSONPath only selects. If you need a result list, JSONPath is concise and works almost everywhere inside tools you already use. If you need to compute or restructure, reach for jq or code.
| Task | JSONPath | jq |
|---|---|---|
| All titles | $.store.books[*].title |
.store.books[].title |
| Cheap books | $.store.books[?(@.price<10)] |
.store.books[] | select(.price<10) |
| Last book | $.store.books[-1] |
.store.books[-1] |
| Sum of prices | not possible | [.store.books[].price] | add |
Tips
- Start broad, then narrow. Test
$..titlefirst, then add structure. - Quote odd keys. Use
$['my key']for anything that isn’t a simple identifier. - Beware
..on big documents. Recursive descent visits every node, which is slow on huge files. - Validate first. If the path matches nothing and you can’t see why, check the JSON is valid and shaped as you expect. See common JSON errors.
Related guides
To turn query results into a table, see how to convert Postman JSON to CSV. To explore a very large file by query, read how to view large JSON files.