What Is JSONPath?
JSONPath is a query language for extracting values from JSON documents. Originally proposed by Stefan Goessner in 2007 as an analog to XPath for XML, JSONPath lets you write expressions like $.store.book[*].author to select all author fields inside a book array without writing loops or manual traversal code. The language was standardized in February 2024 as RFC 9535, published by the IETF.
A JSONPath expression always starts with $ representing the root of the document. From there you chain selectors: dot notation for object keys, bracket notation for array indices, wildcards for all children, and the recursive descent operator (..) to search through every level of nesting. Filter expressions like [?(@.price < 10)] let you select elements based on conditions evaluated against their values.
JSONPath is used in API testing tools like Postman, observability platforms like Datadog and Splunk, workflow engines like Apache NiFi, and programming libraries across JavaScript, Python, Go, Java, and C#. Testing your expressions against real data before embedding them in code or config files prevents silent failures when the JSON structure does not match your assumptions.
Why Use This JSONPath Tester?
Writing JSONPath expressions by hand is error-prone. A missing dot, wrong bracket type, or incorrect filter syntax can return empty results with no error message. This tool gives you immediate visual feedback on what your expression matches.
JSONPath Use Cases
JSONPath Syntax Reference
RFC 9535 defines the standard JSONPath syntax. The table below covers the operators you will use in most queries. All expressions start with $ (the root node) and chain one or more selectors to navigate the document structure.
| Operator | Description | Example |
|---|---|---|
| $ | Root element | $.store |
| .key | Child property | $.store.book |
| [n] | Array index (zero-based) | $.store.book[0] |
| [*] | All elements in array/object | $.store.book[*] |
| .. | Recursive descent | $..author |
| [start:end] | Array slice | $.store.book[0:2] |
| [?()] | Filter expression | $.store.book[?(@.price<10)] |
| @ | Current node (inside filter) | $.store.book[?(@.isbn)] |
JSONPath vs jq vs XPath
JSONPath, jq, and XPath solve the same problem (querying structured data) for different formats and use cases. JSONPath targets JSON and is available as a library in most languages. jq is a standalone CLI tool with its own Turing-complete filter language. XPath operates on XML and is part of the W3C specification stack.
| Feature | JSONPath | jq | XPath |
|---|---|---|---|
| Data format | JSON | JSON | XML |
| Access first element | $.store.book[0] | .store.book[0] | /store/book[1] |
| Recursive search | $..price | .. | .price? | //price |
| Filter expression | [?(@.price<10)] | select(.price < 10) | [price<10] |
| Specification | RFC 9535 | stedolan.github.io | W3C XPath 3.1 |
Code Examples
How to evaluate JSONPath expressions in popular languages and tools. Each example uses the same bookstore JSON structure for comparison.
import { JSONPath } from 'jsonpath-plus';
const data = {
store: {
book: [
{ title: 'Moby Dick', price: 8.99 },
{ title: 'The Great Gatsby', price: 12.99 }
]
}
};
// Get all book titles
JSONPath({ path: '$.store.book[*].title', json: data });
// → ['Moby Dick', 'The Great Gatsby']
// Recursive descent — find every price in the document
JSONPath({ path: '$..price', json: data });
// → [8.99, 12.99]
// Filter — books under $10
JSONPath({ path: '$.store.book[?(@.price < 10)]', json: data });
// → [{ title: 'Moby Dick', price: 8.99 }]from jsonpath_ng.ext import parse
import json
data = {
"store": {
"book": [
{"title": "Moby Dick", "price": 8.99},
{"title": "The Great Gatsby", "price": 12.99}
]
}
}
# Get all book titles
expr = parse("$.store.book[*].title")
titles = [match.value for match in expr.find(data)]
# → ['Moby Dick', 'The Great Gatsby']
# Recursive descent — all prices
expr = parse("$..price")
prices = [match.value for match in expr.find(data)]
# → [8.99, 12.99]
# Filter — books under $10
expr = parse("$.store.book[?price < 10]")
cheap = [match.value for match in expr.find(data)]
# → [{"title": "Moby Dick", "price": 8.99}]package main
import (
"fmt"
"github.com/ohler55/ojg/jp"
"github.com/ohler55/ojg/oj"
)
func main() {
src := `{
"store": {
"book": [
{"title": "Moby Dick", "price": 8.99},
{"title": "The Great Gatsby", "price": 12.99}
]
}
}`
obj, _ := oj.ParseString(src)
// Get all book titles
expr, _ := jp.ParseString("$.store.book[*].title")
results := expr.Get(obj)
fmt.Println(results)
// → [Moby Dick The Great Gatsby]
// Recursive descent — all prices
expr2, _ := jp.ParseString("$..price")
fmt.Println(expr2.Get(obj))
// → [8.99 12.99]
}# jq uses its own syntax, not JSONPath, but solves the same problem.
# Mapping common JSONPath patterns to jq:
# $.store.book[*].title → get all titles
echo '{"store":{"book":[{"title":"Moby Dick"},{"title":"Gatsby"}]}}' | \
jq '.store.book[].title'
# → "Moby Dick"
# → "Gatsby"
# $..price → recursive descent for "price" keys
echo '{"a":{"price":1},"b":{"price":2}}' | \
jq '.. | .price? // empty'
# → 1
# → 2
# Filter: books where price < 10
echo '{"store":{"book":[{"title":"A","price":8},{"title":"B","price":12}]}}' | \
jq '.store.book[] | select(.price < 10)'
# → {"title":"A","price":8}