If you have ever had to pull a specific value from a deeply nested API response, you have probably written something like this:
const city = response.user.address.city;
// works fine, until user.address is undefined
Or a chain of map and filter calls to grab every price from a list of products. JSONPath is a query language for JSON that handles these cases in a single expression, similar to how XPath works for XML.
The basic syntax
JSONPath expressions start with $, which represents the root of the document.
-
.keyselects a named property -
['key']same, but works with spaces and special characters -
[*]selects all items in an array -
..keyrecursively searches all descendants for that key -
[0],[-1]index and last-item access -
[0:3]slice notation -
?(@.price > 10)filter expression using@to reference the current node
That covers most of what you will use day to day.
Real examples
Say you have this JSON from an e-commerce API:
{
"store": {
"books": [
{ "title": "Clean Code", "price": 35, "inStock": true },
{ "title": "The Pragmatic Programmer", "price": 45, "inStock": false },
{ "title": "Refactoring", "price": 40, "inStock": true }
]
}
}
Get all book titles:
$.store.books[*].title
Returns: ["Clean Code", "The Pragmatic Programmer", "Refactoring"]
Get only books that are in stock:
$.store.books[?(@.inStock == true)]
Returns the two books where inStock is true.
Find every price field anywhere in the document:
$..price
The .. recursive descent searches every level. Useful when the structure is inconsistent or you don't know how deep the field lives.
When JSONPath is actually useful
API response drilling. When a third-party API returns a large blob and you need three fields out of it, a JSONPath expression is cleaner than chaining property accesses with null checks at every level.
Log analysis. If you're parsing structured JSON logs and want to pull specific fields across thousands of records, write the query once and apply it.
Testing and assertions. Some test frameworks let you assert against JSONPath expressions, which is cleaner than destructuring the response object just to check one value.
Config files with complex structure. If your app reads a deep config and you want all entries matching a condition, JSONPath can save you writing a recursive search by hand.
When it is overkill
For simple access like response.data.items, use dot notation. JSONPath adds a dependency and a learning curve for cases where obj.a.b.c is perfectly readable.
Also worth knowing: JSONPath implementations differ across languages and libraries. The spec has gray areas, especially around filter expressions. Test your expressions against the actual runtime you plan to use.
Try it without installing anything
Before committing a JSONPath expression to code, it helps to test it against real data first. The JSONPath tester runs in your browser, no install needed. Paste your JSON on the left, type the expression, and see the matching results highlighted immediately.
It is useful for learning how the selectors behave and for debugging expressions before they end up in production code.
Libraries by language
-
JavaScript/Node.js:
jsonpath-plus(broadest spec coverage),jsonpath -
Python:
jsonpath-ng - Java: Jayway JsonPath
-
Go:
github.com/PaesslerAG/jsonpath
Different libraries have different levels of spec support, particularly around filter expressions and recursive descent edge cases. Check the library's test suite against your use case before picking one.
JSONPath is not something you reach for every day, but knowing the syntax means you never have to write a custom recursive traversal just to find a nested field. Worth spending 20 minutes with it.
Top comments (0)