What JSONPath is for
JSONPath is a query language for picking values out of a JSON document. Instead of writing loops and null checks, you describe the path to the data and get back every value that matches. It was proposed by Stefan Goessner in 2007, spread through many slightly different libraries, and was standardized as RFC 9535 in 2024.
You will meet JSONPath in API testing tools, kubectl output formatting, AWS Step Functions, log processors, and integration platforms. Because those tools do not all support the same features, the most reliable habit is to test an expression against real sample data before relying on it.
The sample document
Every example on this page runs against this small store catalog. Paste it into a JSONPath tester and follow along.
{
"store": {
"name": "City Books",
"books": [
{ "title": "Clean Code", "author": "Robert Martin", "price": 32, "tags": ["programming"] },
{ "title": "Dune", "author": "Frank Herbert", "price": 9, "tags": ["fiction", "classic"] },
{ "title": "Sapiens", "author": "Yuval Noah Harari", "price": 18, "tags": ["history"] },
{ "title": "Refactoring", "author": "Martin Fowler", "price": 41, "tags": ["programming"] }
],
"address": { "city": "Pune", "country": "India" }
}
}The basics: root, children, and arrays
Every expression starts at $, the root of the document. From there you step into children with dot notation or bracket notation, and into arrays with zero-based indexes.
| Expression | Result | Meaning |
|---|---|---|
$.store.name | "City Books" | Dot notation for a child member |
$['store']['name'] | "City Books" | Bracket notation, needed for keys with spaces or symbols |
$.store.books[0].title | "Clean Code" | First element of an array |
$.store.address.city | "Pune" | Nested objects |
Use bracket notation whenever a key contains spaces, hyphens, dots, or starts with a digit, for example $['order-id'] or $['2024']. Dot notation only works for keys that look like simple identifiers.
Wildcards and projections
The wildcard * selects every member of an object or every element of an array. Combined with a following path it acts as a projection: it collects the same field from every element.
| Expression | Result |
|---|---|
$.store.books[*].title | ["Clean Code", "Dune", "Sapiens", "Refactoring"] |
$.store.books[*].price | [32, 9, 18, 41] |
$.store.address.* | ["Pune", "India"] |
$.store.books[*].tags[0] | ["programming", "fiction", "history", "programming"] |
Projections are the workhorse of everyday JSONPath. Pulling every id from an API response, every email from a user list, or every status from a set of jobs is a single expression.
Recursive descent
Two dots, .., search every level of the document. $..price finds every price field no matter how deeply it is nested, and $..tags finds every tags array.
| Expression | Result |
|---|---|
$..author | ["Robert Martin", "Frank Herbert", "Yuval Noah Harari", "Martin Fowler"] |
$..city | ["Pune"] |
Recursive descent is ideal for exploring an unfamiliar document, but it can return more than you expect when the same key appears in unrelated places. In production configuration, prefer an explicit path so that unrelated changes elsewhere in the document cannot change the result.
Array slices and negative indexes
Slices use the Python-style [start:end:step] syntax, where end is exclusive. Negative indexes count from the end of the array.
| Expression | Result |
|---|---|
$.store.books[0:2].title | ["Clean Code", "Dune"] |
$.store.books[-1].title | "Refactoring" |
$.store.books[-2:].title | ["Sapiens", "Refactoring"] |
$.store.books[::2].title | ["Clean Code", "Sapiens"] |
Filter expressions
Filters select array elements that match a condition. Inside the filter, @ refers to the element being tested. Classic implementations write filters as [?(...)]; RFC 9535 also accepts [?...] without the parentheses.
| Expression | Result |
|---|---|
$.store.books[?(@.price < 20)].title | ["Dune", "Sapiens"] |
$.store.books[?(@.author == 'Martin Fowler')].price | [41] |
$.store.books[?(@.price > 10 && @.price < 40)].title | ["Clean Code", "Sapiens"] |
Filter support varies more than any other feature. Comparison operators, existence checks such as [?(@.isbn)], regular expressions, and functions like length() are implemented differently, or not at all, across libraries. Some tools also disable filters entirely because older implementations evaluated them as code.
JSONPath in real tools
Many tools embed JSONPath with small twists, so it pays to recognize the variations. Kubernetes kubectl uses a JSONPath template syntax: expressions sit inside curly braces and usually omit the leading $. To list the names of all pods, for example:
kubectl get pods -o jsonpath='{.items[*].metadata.name}'AWS Step Functions uses paths such as $.detail.orderId to select parts of the state passed between steps, and many API testing and monitoring tools let you extract a value from a response with a JSONPath expression before asserting on it. In each case, the core syntax from this page carries over; what changes is support for advanced features such as filters and functions, so check the documentation of the tool you are using.
What the UtiliStudio JSONPath Tester supports
The JSONPath Tester uses a safe, declarative evaluator that never executes code. It supports the core syntax that covers most everyday lookups, and deliberately rejects filters and script expressions.
| Feature | Example | Supported in the tester |
|---|---|---|
| Root and dot notation | $.store.name | Yes |
| Bracket notation | $['store']['name'] | Yes |
| Array index | $.store.books[0] | Yes |
| Wildcards and projections | $.store.books[*].title | Yes |
| Array length | $.store.books.length | Yes (extension, not part of RFC 9535) |
| Recursive descent | $..price | Not yet |
| Slices and negative indexes | $.store.books[-1] | Not yet |
| Filters | [?(@.price < 20)] | No, by design |
If your production tool supports filters, use the tester to confirm the path up to the array, then add the filter in your target tool and check the result there.
Tips for writing reliable expressions
- Build incrementally. Start with
$, add one step at a time, and check the result after each step. - Expect a list. JSONPath returns every match, so results are a list even when there is one value, and an empty list when nothing matches.
- Check case and spelling first. Most empty results come from a typo in a key, the wrong letter case, or treating an object as an array.
- Know your flavor. Test with the same implementation your production tool uses, especially for filters.
- Consider JSON Pointer for single values. A pointer such as
/store/books/0/titleaddresses exactly one location and is what JSON Schema errors and JSON Patch use.
Keep learning
- Common JSON errors and how to fix them
- JSON vs YAML vs TOML: which format should you use?
- JSON Formatter: Beautify, minify and validate JSON with syntax highlighting.