{}JSON FYI

JSONPath cheatsheet: selectors, wildcards, and filters

JSONPath reference: root, dot/bracket, wildcards, recursive descent, slices, filters, and RFC 9535 functions — with the canonical spec examples.

·9 min read

What is JSONPath and how do I write one?

JSONPath is a query language for JSON — the JSON equivalent of XPath for XML. A query is a chain of segments that starts at the root $ and selects nodes step by step: .name picks a child, [*] every element, ..name matches at any depth, and [?…] filters. The result is a nodelist — zero or more matching values. As of February 2024 the syntax is standardized as RFC 9535. This page is the complete reference, with the canonical examples from the spec.

$..book[?@.price < 10].title$rootwhole document..bookdescendantmatch at any depth[?@.price < 10]filter selector@ = current node.titlename selectorchild by keyEach segment selects nodes from the previous result — the output is a nodelist (zero or more matches).

The example document

Every query below runs against this document — the bookstore example from RFC 9535, so you can check the results against the standard itself.

{
  "store": {
    "book": [
      { "category": "reference", "author": "Nigel Rees",     "title": "Sayings of the Century", "price": 8.95 },
      { "category": "fiction",   "author": "Evelyn Waugh",   "title": "Sword of Honour",        "price": 12.99 },
      { "category": "fiction",   "author": "Herman Melville","title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 },
      { "category": "fiction",   "author": "J. R. R. Tolkien","title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 }
    ],
    "bicycle": { "color": "red", "price": 399 }
  }
}

Selecting children: dot vs bracket notation

Two ways to name a child, and they are interchangeable. Use bracket notation when a key contains spaces, dots, or other characters that break dot notation.

$.store.book        // dot notation
$['store']['book']  // bracket notation (identical result)
$["odd key.name"]   // bracket notation for awkward keys

Wildcards: selecting every child

A wildcard selects every member of an object or every element of an array — one level deep.

$.store.*           // every value in "store": the book array + the bicycle
$.store.book[*].author  // the author of every book
$.store.book.*      // same as [*] on an array

Recursive descent: matching at any depth

Two dots (..) is the descendant segment — it searches the whole subtree, not just direct children. This is what makes JSONPath concise for deeply nested data.

$..author           // every author, anywhere in the document
$..price            // every price: all 4 books + the bicycle
$..book[*]          // every book object
$..*                // every value in the entire document

Array indexing and slices

Arrays are zero-based. RFC 9535 also standardizes negative indices (counting from the end) and Python-style slices.

$..book[0]          // first book
$..book[-1]         // last book (negative index)
$..book[0,2]        // first and third book (a union of indices)
$..book[:2]         // slice: first two books  [start:end]
$..book[1:3]        // second and third
$..book[::2]        // every other book  [start:end:step]

Filter expressions

A filter [?…] keeps only the nodes for which a test is true. Inside the filter, @ refers to the current node being tested (while $ still refers to the whole document).

$..book[?@.price < 10]        // books cheaper than 10
$..book[?@.isbn]              // books that HAVE an isbn field
$..book[?@.category == 'fiction']
$..book[?@.price < 10 && @.category == 'fiction']  // combine with && ||

Watch the parentheses — this is the #1 portability gotcha.

$..book[?@.price < 10]     // RFC 9535 — no parens around the test
$..book[?(@.price < 10)]   // Goessner-2007 / Jayway / most JS libs — parens required

RFC 9535 writes filters without wrapping parentheses (parentheses are only for grouping sub-expressions, e.g. [?(@.a || @.b) && @.c]). The original 2007 syntax and popular libraries like Jayway and jsonpath-plus require the ?(…) form. If a query fails, try toggling the parentheses first.

Functions (RFC 9535)

RFC 9535 adds five function extensions usable inside filters. These are the newest part of the spec and not all libraries implement them yet.

  • length(@) — length of a string, array, or object
  • count(@..*) — number of nodes a query matched
  • match(@.title, "Sword.*") — whole string matches a regexp
  • search(@.name, "^A") — string contains a match for a regexp
  • value(@.a) — turn a single-node result into a comparable value
$..book[?length(@.title) > 15]   // titles longer than 15 chars
$..book[?search(@.author, 'Tolkien')]

Test these expressions on your own JSON →

Paste a document, type any JSONPath, and see every match highlighted live — wildcards, recursive descent, slices, and filters all supported. Runs entirely in your browser.

Open JSONPath Tester →

JSONPath vs XPath vs JMESPath vs jq

  • JSONPath — the JSON analogue of XPath; now standardized as RFC 9535. Best for "pull these nodes out of this document".
  • JMESPath — a stricter, spec-first query language used across the AWS CLI and SDKs; different syntax, supports projections and transforms.
  • jq — a full stream-processing language (its own syntax) for transforming JSON on the command line, not just selecting.
  • XPath — the original, for XML. JSONPath borrows its ideas but is not compatible.

Pick what your tooling already supports. If you just need to see the shape of a document before writing a path, open the tree viewer — click any node to copy its exact JSONPath. New to the format? Start with what is JSON and the data types reference; if a query never matches, the document may not be valid — check it against common JSON errors first.

Frequently asked questions

Is JSONPath a standard?+

Yes, as of February 2024. RFC 9535 ("JSONPath: Query Expressions for JSON") standardizes the syntax and semantics. Before that, the de-facto reference was Stefan Gössner's 2007 article, which most libraries implemented with small differences.

What does @ mean in JSONPath?+

@ is the current node inside a filter expression — the item being tested. $ always refers to the root of the whole document, so you can compare a node against a value elsewhere in the tree.

Why does my filter with [?(@.price < 10)] fail?+

Parenthesis style differs by implementation. RFC 9535 uses [?@.price < 10] without wrapping parentheses; the older Goessner syntax and libraries like Jayway and jsonpath-plus require [?(@.price < 10)]. Try toggling the parentheses.

Does JSONPath support negative array indices?+

RFC 9535 standardizes them — [-1] is the last element and slices like [-2:] work. Older implementations vary, so test against your specific library if you rely on it.

What does a JSONPath query return — one value or many?+

A nodelist: zero, one, or many matching nodes. Even a query that looks like it targets a single value returns a list, so your code should handle the multi-match case.

JSONPath vs jq — which should I use?+

Use JSONPath to select nodes out of a document (it maps cleanly onto library calls in most languages). Use jq when you need to transform, reshape, or compute over JSON on the command line — it's a full language, not just a selector.

Related tools & guides