When you have a large, nested JSON, navigating through it manually (accessing property by property in code) gets tedious. JSONPath solves this: it’s a query language for JSON, similar in spirit to XML’s XPath, that lets you select specific data using a short syntax, without writing loops or multiple lines of property access.
The example JSON
To illustrate the examples in this post, we’ll use this document:
{
"store": {
"name": "Example Store",
"employees": [
{ "name": "Ana", "role": "manager", "salary": 8000 },
{ "name": "John", "role": "sales", "salary": 3000 },
{ "name": "Maria", "role": "sales", "salary": 3200 }
]
}
}
Basic syntax
A JSONPath expression always starts with $, which represents the root of the document.
$.store.name
This returns "Example Store". It’s equivalent to accessing document.store.name directly in code, except as a string expression that can be evaluated dynamically.
Accessing items in an array
$.store.employees[0].name
Returns "Ana", the first employee in the array (indexes start at 0, like in most programming languages).
Selecting every item in an array
$.store.employees[*].name
The * selects every item. This returns an array with all the names: ["Ana", "John", "Maria"].
Conditional filters
The most powerful part of JSONPath is filtering items based on a condition, using the [?(...)] syntax.
$.store.employees[?(@.salary > 3000)]
This returns every employee with a salary greater than 3000. The @ inside the filter represents the current item being evaluated (similar to the root $, but in the filter’s local context).
Another example, filtering by role:
$.store.employees[?(@.role == 'sales')]
Returns John and Maria, both with the role “sales.”
Recursive search (descendant search)
The .. operator searches for a key at any depth in the document, without needing to know the exact path.
$..name
This returns every name value in the entire document, both "Example Store" and each employee’s name: ["Example Store", "Ana", "John", "Maria"]. Very useful when you don’t know (or don’t want to worry about) the exact depth where a key appears.
Combining filters with multiple criteria
$.store.employees[?(@.role == 'sales' && @.salary > 3000)]
Returns only Maria, since she’s the only salesperson with a salary above 3000.
Where JSONPath is used in practice
- APIs and automation tools: tools like Postman and n8n use JSONPath (or a variation of it) to extract specific values from API responses without writing code
- Structured logs: querying logs in JSON format without needing to load the entire document into a program
- Automated tests: validating that an API response contains specific values at specific paths
- Data manipulation libraries: languages like Python (
jsonpath-ng), JavaScript (jsonpath-plus), and Java (Jayway JsonPath) implement JSONPath as a library
A point worth noting: there’s no single standard
Unlike JSON itself (which has a single, well-defined spec, RFC 8259), JSONPath has no single official specification followed by every implementation. There are variations between different libraries, especially in the syntax for more advanced filters. It’s always worth checking the specific documentation for the library or tool you’re using, since the examples in this post follow the most common syntax, but may have small differences depending on where you apply them.
Quick checklist
- Remembered that expressions always start with
$(the document’s root)? - Using
[*]when you need every item in an array, instead of accessing index by index? - Using
..when you don’t know (or don’t want to worry about) the exact depth of a key? - Confirmed the specific filter syntax in the documentation of the library/tool you’re using?
If you want to check your JSON’s structure before writing a JSONPath expression, paste it into JSON Validator to visualize it better.