JSONPath is a query language for JSON, similar to how XPath works for XML. Instead of writing nested loops to dig out a value, you write a short path expression. Once you know the syntax, you reach for it constantly. This tutorial covers everything with practical examples.

Our sample data

{
  "store": {
    "books": [
      {"title": "Clean Code", "price": 35, "inStock": true},
      {"title": "The Pragmatic Programmer", "price": 45, "inStock": false},
      {"title": "Refactoring", "price": 40, "inStock": true}
    ]
  }
}

The root: $

Every JSONPath expression starts with $, which represents the root of the document. From there you navigate with dots and brackets.

$                    // the whole document
$.store              // the store object
$.store.books        // the books array

Accessing array elements

$.store.books[0]         // first book
$.store.books[-1]        // last book
$.store.books[0,2]       // first and third
$.store.books[0:2]       // slice: first two

The wildcard: *

[*] means "all elements." This is how you pull one field from every object without a loop:

$.store.books[*].title
// ["Clean Code", "The Pragmatic Programmer", "Refactoring"]

Recursive descent: ..

The .. operator searches every level of the document. Use it when you do not know exactly where a key lives:

$..price        // every price anywhere in the document
$..email        // every email field at any depth

This is invaluable for exploring unfamiliar API schemas or debugging inconsistent nesting.

Filter expressions: ?()

The most powerful feature. ?() filters by a condition, where @ refers to the current element:

// All books in stock
$.store.books[?(@.inStock == true)]

// Books cheaper than 42
$.store.books[?(@.price < 42)]

// Combine conditions
$.store.books[?(@.price < 42 && @.inStock == true)]

// Check a key exists
$.store.books[?(@.discount)]

Test JSONPath expressions in your browser

Paste your JSON, type a JSONPath query, and see matching results instantly. No install, no upload — free and private.

Open tool →

Why JSONPath beats writing loops

Compare extracting every in-stock book. Without JSONPath:

# Python — five lines, easy to get wrong
results = []
for book in data["store"]["books"]:
    if book["inStock"]:
        results.append(book)

With JSONPath it is one self-documenting line: $.store.books[?(@.inStock == true)]. Anyone reading it immediately knows what you are after.

JSONPath vs jq vs JMESPath

  • JSONPath — general-purpose querying. Best for extracting values in application code. Standardized in RFC 9535 (2024).
  • jq — command-line tool with its own language. Most powerful, supports transformations, not just queries. Best for shell scripts.
  • JMESPath — used by the AWS CLI. More rigorously specified. Best for AWS and consistent cross-platform use.

Library support

Use jsonpath-plus in JavaScript and jsonpath-ng in Python — together they cover 95% of use cases. Note that older libraries differ on edge cases like negative indices and recursive descent; RFC 9535 is improving interoperability. Standard JSONPath is read-only — for modifications, query first, then mutate with your language's native tools.