Back to Blog

JSONPath: The Complete Guide to Querying JSON Data

Apr 1, 20268 min read

JSONPath is a query language for JSON, analogous to XPath for XML. It lets you navigate into complex, deeply nested JSON structures and extract exactly the values you need using a concise path expression. Whether you are filtering API responses, writing test assertions, or transforming data pipelines, JSONPath is an essential tool to have in your toolkit.

JSONPath Basics: The Root and Dot Notation

Every JSONPath expression starts with $, which represents the root of the JSON document. From there, you navigate using dots (.) for child access or square brackets ([]) for subscript access.

Example JSON document
{
  "store": {
    "name": "The Bookstore",
    "books": [
      { "title": "Clean Code", "author": "Robert Martin", "price": 29.99, "inStock": true },
      { "title": "The Pragmatic Programmer", "author": "Hunt & Thomas", "price": 39.99, "inStock": false },
      { "title": "Refactoring", "author": "Martin Fowler", "price": 34.99, "inStock": true }
    ],
    "location": {
      "city": "New York",
      "zip": "10001"
    }
  }
}
ExpressionResult
$The entire document
$.store.name"The Bookstore"
$.store.location.city"New York"
$.store.books[0]First book object
$.store.books[0].title"Clean Code"
$.store.books[-1]Last book (Refactoring)
$.store.books[0,1]First two books
$.store.books[0:2]Books at index 0 and 1 (slice)

Wildcards: Selecting All Children

The wildcard * matches any child element. Use it to select all items in an array or all properties of an object.

Wildcard examples
$.store.books[*]          → all books (array of 3 objects)
$.store.books[*].title    → ["Clean Code", "The Pragmatic Programmer", "Refactoring"]
$.store.books[*].price    → [29.99, 39.99, 34.99]
$.store.*                 → all values under "store" (books array + location object + name)

Recursive Descent: Searching Deep Structures

The double-dot operator .. (recursive descent) searches the entire document tree for a key, regardless of depth. This is extremely useful when you don't know exactly how deep a value is nested.

Recursive descent examples
$..title           → all "title" values anywhere in the document
$..price           → all "price" values at any depth
$..books[0].title  → "title" of the first element of any "books" array found anywhere

Filter Expressions: Conditional Selection

Filter expressions use the syntax [?()] to select array elements that satisfy a condition. Use @ to refer to the current element.

Filter expression examples
$.store.books[?(@.inStock == true)]
  → [{ "title": "Clean Code", ... }, { "title": "Refactoring", ... }]

$.store.books[?(@.price < 35)]
  → [{ "title": "Clean Code", "price": 29.99 }, { "title": "Refactoring", "price": 34.99 }]

$.store.books[?(@.author =~ /Martin/)]
  → books where author contains "Martin" (regex, supported by some implementations)

$.store.books[?(@.price >= 30 && @.inStock == true)]
  → books costing $30+ that are in stock

Test your JSONPath expressions live

Use our JSONPath Tool to paste your JSON and run expressions interactively. Results are highlighted in the tree view instantly.

Bracket Notation vs Dot Notation

Both notations are equivalent for simple property access. Use bracket notation when a key contains spaces, hyphens, or other special characters that would break dot notation.

Bracket notation for special keys
$.store.name                   ← dot notation
$['store']['name']             ← bracket notation (equivalent)

$['store']['location']['city'] ← required for keys with spaces:
$['user-agent']                ← key with hyphen — dot notation would fail
$['@context']                  ← key starting with @ (common in JSON-LD)

JSONPath in Different Languages

JSONPath in JavaScript (jsonpath-plus)
import { JSONPath } from 'jsonpath-plus';

const result = JSONPath({ path: '$.store.books[?(@.inStock==true)].title', json: data });
// → ["Clean Code", "Refactoring"]
JSONPath in Python (jsonpath-ng)
from jsonpath_ng import parse

expr = parse('$.store.books[?(@.inStock == true)].title')
matches = [match.value for match in expr.find(data)]
# → ["Clean Code", "Refactoring"]
JSONPath with jq (CLI alternative)
# jq uses a different but similar syntax
cat data.json | jq '.store.books[] | select(.inStock == true) | .title'
# → "Clean Code"
#    "Refactoring"

JSONPath vs jq: What's the Difference?

FeatureJSONPathjq
StandardRFC 9535 (2024)No formal standard
Language supportMany libraries in JS, Python, Java, Go...CLI tool + some libraries
Syntax$.store.books[*].title.store.books[].title
Filter expressions[?(@.price < 35)]select(.price < 35)
Best forProgrammatic queries inside appsCLI data wrangling and shell scripts
OutputArray of matched valuesStreaming newline-delimited values

Common JSONPath Patterns

  • Get all IDs: $..id — find every id field recursively
  • First N items: $.items[0:5] — array slice, first 5 elements
  • Last item: $.items[-1] — last element of an array
  • Nested filter: $.users[?(@.address.country == 'US')]
  • Multiple keys: $.books[*]['title','author'] — select only title and author
  • Check key exists: $.items[?(@.discount)] — items where 'discount' key exists

Run JSONPath expressions on your JSON

Paste any JSON document and write JSONPath queries interactively. Results update instantly as you type.