Skip to content
Tools

JSONPath Cheat Sheet with Examples

· 4 min read

JSONPath is a query language for selecting parts of a JSON document: $ is the root, .key or ['key'] selects a child, [*] selects all elements, .. searches at any depth, and [?@.price < 10] filters by a condition. It was standardized as RFC 9535 in 2024; try every example below in the JSONPath tester.

Sample document

All examples use this document:

{
  "store": {
    "books": [
      { "title": "Dune", "author": "Frank Herbert", "price": 9.99, "tags": ["sci-fi"] },
      { "title": "Emma", "author": "Jane Austen", "price": 4.5, "tags": ["classic", "romance"] },
      { "title": "Neuromancer", "author": "William Gibson", "price": 12, "isbn": "0-441-56956-0" }
    ],
    "bicycle": { "color": "red", "price": 199 }
  }
}

Syntax reference

ExpressionMeaningResult on the sample
$The root nodeThe whole document
$.store.bicycle.colorChild by name (dot notation)"red"
$['store']['bicycle']Child by name (bracket notation)The bicycle object
$.store.books[0].titleArray index (zero-based)"Dune"
$.store.books[-1].titleNegative index counts from the end"Neuromancer"
$.store.books[*].authorWildcard: every elementAll three authors
$.store.*Wildcard: every member of an objectThe books array and the bicycle object
$..priceRecursive descent: price at any depth9.99, 4.5, 12, 199
$.store.books[0,2].titleMultiple indexes (union)"Dune", "Neuromancer"
$.store.books[0:2].titleSlice: start inclusive, end exclusive"Dune", "Emma"
$.store.books[::2].titleSlice with step"Dune", "Neuromancer"
$.store.books[?@.isbn].titleFilter: has the member"Neuromancer"
$.store.books[?@.price < 10].titleFilter: comparison"Dune", "Emma"
$..books[?@.author == 'Jane Austen'].titleFilter: equality"Emma"

A JSONPath query always returns a list of matches (a "nodelist"), even when it matches one value or none. Tools differ in whether they unwrap single results.

Filter expressions

Inside [? ], @ is the current element being tested. You can combine conditions with &&, || and !, and group with parentheses.

$.store.books[?@.price >= 5 && @.price <= 10].title     -> "Dune"
$.store.books[?@.tags && !@.isbn].title                  -> "Dune", "Emma"
$.store.books[?@.author == 'Frank Herbert' || @.price > 10].title
                                                         -> "Dune", "Neuromancer"

Older implementations based on Stefan Goessner's original 2007 article write filters with parentheses: $..books[?(@.price < 10)]. RFC 9535 accepts the parenthesized form too, so it is the most portable way to write a filter.

Functions (RFC 9535)

FunctionExampleMatches
length()$.store.books[?length(@.tags) > 1].title"Emma"
count()$.store[?count(@.*) > 2]Members of store with more than two children
match()$.store.books[?match(@.title, 'D.*')].title"Dune" (whole string must match)
search()$.store.books[?search(@.author, 'Austen')].title"Emma" (substring match)
value()$.store.books[?value(@..price) > 10].titleConverts a single-node result to a value for comparison

match and search use the I-Regexp dialect (RFC 9485), a portable subset of regular expressions. Older libraries often support =~ instead, with their own regex flavor.

Common recipes

TaskExpression
All values of a key anywhere$..id
First item of every list named items$..items[0]
Objects where a flag is true$.users[?@.active == true]
Items missing a field$.users[?!@.email]
Last N items$.events[-3:]
A key with a dash or space$['content-type'] or $.headers['x-request-id']

Gotchas

  • Implementations differ. Before RFC 9535 there was no standard, so libraries disagree on details like filter syntax, regex support and how results are returned. Check which version your library implements.
  • String quotes. RFC 9535 accepts single or double quotes inside expressions. Single quotes are easier when the query itself is embedded in a JSON string or a shell command.
  • Recursive descent is expensive on large documents because it visits every node. Prefer an explicit path when you know it.
  • Keys with dots. $.a.b means nested keys. For a key literally named a.b, use $['a.b'].
  • No parent selector or transformation in the standard. JSONPath selects; it does not reshape output. For that, use jq (see jq vs JSONPath).

Finding the path to a value

The quickest way to write a query on an unfamiliar document is to find the value in a tree view and copy its path. The JSON viewer lets you click any node and copy a path you can paste into the JSONPath tester, then generalize it with wildcards or filters.

FAQ

What does $ mean in JSONPath?

$ is the root of the document. Every query starts from it, for example $.store.books.

What is the difference between . and .. in JSONPath?

. selects a direct child. .. (recursive descent) selects matching members at any depth below the current node.

How do I filter an array in JSONPath?

Use a filter selector: $.items[?@.price < 10]. @ is the current element. Older libraries need parentheses: [?(@.price < 10)].

Is JSONPath standardized?

Yes. RFC 9535, published by the IETF in February 2024, defines JSONPath. Many existing libraries predate it and behave slightly differently.

Is JSONPath the same as JSON Pointer?

No. JSON Pointer (RFC 6901), such as /store/books/0/title, identifies exactly one location and has no wildcards or filters. JSONPath is a query language that can return many matches.

More JSON guides