15 min read

JSONPath Tutorial: Query JSON Like a Pro

Master the JSONPath query language with practical examples. Learn every operator, write filter expressions, extract data from real API responses, and see how JSONPath compares to jq.

What Is JSONPath and Why You Need It

JSONPath is a query language for JSON data. It lets you write an expression that extracts specific values from a JSON document without writing custom parsing code. Think of it as XPath for XML, but for JSON.

Here is the problem JSONPath solves. You have an API response with 200 lines of nested JSON. You need the email address of every user whose account is active. Without JSONPath, you write a loop, check conditions, and extract values manually. With JSONPath, you write one expression:

$.users[?(@.active == true)].email

That expression says: start at the root ($), go into the users array, filter for elements where active is true, and return the email field from each match. One line, no loops, no conditionals.

JSONPath is used in:

JSONPath was formalized as RFC 9535 (published February 2024), giving it an official specification after years of informal use with varying implementations. If you work with JSON regularly, JSONPath is a tool you should know. Let us start with the operators.

The Complete JSONPath Operator Reference

Every JSONPath expression starts with $, which represents the root of the JSON document. From there, you use operators to navigate the structure and select values. Here is every operator you can use. To test these interactively, paste any JSON into the QTool JSON Viewer and explore the structure visually.

Operator Description Example
$Root element (the entire document)$
.Child operator (dot notation)$.store.book
['...']Child operator (bracket notation)$['store']['book']
[n]Array index (zero-based)$.book[0]
[start:end]Array slice$.book[0:3]
[start:end:step]Array slice with step$.book[0:10:2]
*Wildcard (all children)$.store.*
..Recursive descent (search all levels)$..price
?()Filter expression$[?(@.age > 18)]
@Current element (inside filters)?(@.price < 10)
,Union (multiple indices or names)$.book[0,2,4]
Key Concept

$ is the root, @ is the current element. Every JSONPath expression starts with $. The @ symbol is only used inside filter expressions ?(...) and refers to the element being evaluated. Master these two symbols and the rest follows naturally.

Basic Queries: Navigating JSON Structure

Let us work through progressively complex queries using a sample JSON document. This is a simplified version of the classic "bookstore" example used in the JSONPath specification.

{
  "store": {
    "book": [
      {
        "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
      },
      {
        "category": "reference",
        "author": "Douglas Crockford",
        "title": "JavaScript: The Good Parts",
        "isbn": "978-0596517748",
        "price": 15.99
      },
      {
        "category": "fiction",
        "author": "Ursula K. Le Guin",
        "title": "A Wizard of Earthsea",
        "isbn": "978-0547722023",
        "price": 7.50
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 399.99
    }
  }
}

Now let us query it. Paste this JSON into the QTool JSON Formatter to see it properly indented, then try these expressions.

Dot Notation

$.store.bicycle.color        // "red"
$.store.book[0].title        // "Moby Dick"
$.store.book[1].author       // "J.R.R. Tolkien"

Bracket Notation

$['store']['bicycle']['price']   // 399.99
$['store']['book'][2]['title']   // "JavaScript: The Good Parts"

Bracket notation is required when property names contain spaces, dots, or special characters: $['my property'], $['key.with.dots'].

Wildcard

$.store.book[*].title
// ["Moby Dick", "The Lord of the Rings",
//  "JavaScript: The Good Parts", "A Wizard of Earthsea"]

$.store.*
// Returns both the book array AND the bicycle object

Array Indexing

$.store.book[0]           // First book (Moby Dick)
$.store.book[-1]          // Last book (A Wizard of Earthsea)
$.store.book[0,2]         // First and third books

Filter Expressions: The Power of JSONPath

Filter expressions are the most powerful feature of JSONPath. They let you select elements that match a condition, just like a SQL WHERE clause.

Comparison Operators

// Books cheaper than $10
$.store.book[?(@.price < 10)]
// Returns: Moby Dick ($8.99), A Wizard of Earthsea ($7.50)

// Books in the fiction category
$.store.book[?(@.category == "fiction")]
// Returns: Moby Dick, The Lord of the Rings, A Wizard of Earthsea

// Books NOT in fiction
$.store.book[?(@.category != "fiction")]
// Returns: JavaScript: The Good Parts

Logical Operators

// Fiction books under $10
$.store.book[?(@.category == "fiction" && @.price < 10)]
// Returns: Moby Dick, A Wizard of Earthsea

// Books that are fiction OR under $10
$.store.book[?(@.category == "fiction" || @.price < 10)]
// Returns: all fiction books plus any under $10

Existence Check

// Books that have an ISBN field
$.store.book[?(@.isbn)]
// Returns: all four books (they all have ISBN)

// Use this to filter out incomplete records in real data

String Matching

// Books by authors containing "Tolkien"
$.store.book[?(@.author =~ /Tolkien/)]

// Note: regex support varies between implementations.
// RFC 9535 does not include regex. Check your library's docs.
Pro Tip

Always validate your JSON before writing queries. If your JSON has syntax errors (missing commas, unquoted keys, trailing commas), JSONPath expressions will fail silently or produce unexpected results. Run your data through a JSON formatter first to catch issues.

Array Slicing

Array slicing lets you extract a range of elements from an array using the [start:end:step] syntax. This works like Python list slicing.

$.store.book[0:2]       // First two books (index 0 and 1)
$.store.book[1:3]       // Second and third books
$.store.book[:2]        // First two books (start defaults to 0)
$.store.book[2:]        // Third book onwards (end defaults to length)
$.store.book[-2:]       // Last two books
$.store.book[::2]       // Every other book (step of 2)

Slicing is particularly useful when working with paginated API responses or when you only need a subset of a large array.

Recursive Descent: Search All Levels

The .. operator searches through all levels of nesting to find a key, regardless of how deep it is in the structure. This is powerful when you know what key you want but not where it lives.

// Find ALL prices in the entire document
$..price
// [8.99, 22.99, 15.99, 7.50, 399.99]
// Includes book prices AND bicycle price

// Find ALL authors at any nesting level
$..author
// ["Herman Melville", "J.R.R. Tolkien",
//  "Douglas Crockford", "Ursula K. Le Guin"]

// Find all ISBN values anywhere in the document
$..isbn
// ["0-553-21311-3", "0-395-19395-8",
//  "978-0596517748", "978-0547722023"]

Recursive descent is the operator that saves the most code. Without it, you would need to know the exact path to every price field in a deeply nested document. With .., you say "find this key anywhere" and JSONPath does the work.

Use .. with caution on large documents. It traverses the entire tree, which can be slow on deeply nested structures with thousands of nodes. For performance-critical code, prefer explicit paths when you know the structure.

Real-World API Examples

Let us apply JSONPath to data structures you actually encounter in production. These examples use realistic API responses that you can validate with the QTool JSON Viewer.

GitHub API: Extract Repository Names

// Response from: GET /users/{username}/repos
// Extract all repo names
$[*].name

// Repos with more than 100 stars
$[?(@.stargazers_count > 100)].full_name

// Repos that are not forks
$[?(@.fork == false)].name

// Languages used across all repos
$[*].language

Kubernetes: Pod Queries

// All pod names
$.items[*].metadata.name

// Pods in "Running" state
$.items[?(@.status.phase == "Running")].metadata.name

// Container images across all pods
$.items[*].spec.containers[*].image

// Resource limits for all containers
$..resources.limits

E-Commerce API: Product Queries

// Sample response
{
  "products": [
    {"name": "Laptop", "price": 999, "category": "electronics", "inStock": true, "rating": 4.5},
    {"name": "Keyboard", "price": 79, "category": "electronics", "inStock": true, "rating": 4.8},
    {"name": "Desk", "price": 249, "category": "furniture", "inStock": false, "rating": 4.2},
    {"name": "Monitor", "price": 449, "category": "electronics", "inStock": true, "rating": 4.6}
  ]
}

// In-stock electronics under $500
$.products[?(@.category == "electronics" && @.inStock == true && @.price < 500)]

// Products rated 4.5 or higher
$.products[?(@.rating >= 4.5)].name
// ["Laptop", "Keyboard", "Monitor"]

// All unique categories (get all, deduplicate in code)
$.products[*].category

If you need to convert any of these JSON responses to CSV for analysis in a spreadsheet, the QTool JSON to CSV converter handles nested structures automatically.

JSONPath vs jq: Which Should You Use?

JSONPath and jq solve overlapping but distinct problems. Here is how they compare.

Feature JSONPath jq
Primary useSelect / extract dataSelect, transform, construct data
Learning curveLow (XPath-like)Medium-high (its own language)
EnvironmentLibraries in all languagesPrimarily command line
Data transformationNot supportedFull support (map, reduce, sort, group)
Filter expressionsBasic comparisonsFull programming logic
Output formatArray of matched valuesAny JSON structure
StandardizedRFC 9535No formal standard
String operationsLimitedFull (split, join, regex, format)

Use JSONPath when:

Use jq when:

The Same Query in Both

// "Get titles of fiction books under $10"

// JSONPath
$.store.book[?(@.category == "fiction" && @.price < 10)].title

// jq
.store.book[] | select(.category == "fiction" and .price < 10) | .title

Both produce the same result. JSONPath is shorter. jq is more readable for complex logic. Choose based on your context.

JSONPath Libraries by Language

JavaScript / Node.js

// jsonpath-plus (RFC 9535 compliant)
npm install jsonpath-plus

import { JSONPath } from 'jsonpath-plus';

const data = { store: { book: [/* ... */] } };
const result = JSONPath({ path: '$.store.book[?(@.price < 10)].title', json: data });
console.log(result);
// ["Moby Dick", "A Wizard of Earthsea"]

Python

# jsonpath-ng
pip install jsonpath-ng

from jsonpath_ng.ext import parse

data = {"store": {"book": [{"title": "Moby Dick", "price": 8.99}, ...]}}
expr = parse("$.store.book[?price < 10].title")
matches = [match.value for match in expr.find(data)]
print(matches)
# ["Moby Dick", "A Wizard of Earthsea"]

Java

// Jayway JsonPath
// Maven: com.jayway.jsonpath:json-path:2.9.0

import com.jayway.jsonpath.JsonPath;

String json = "{ ... }";
List<String> titles = JsonPath.read(json, "$.store.book[?(@.price < 10)].title");
System.out.println(titles);
// [Moby Dick, A Wizard of Earthsea]

Go

// PaesslerAG/jsonpath
// go get github.com/PaesslerAG/jsonpath

import "github.com/PaesslerAG/jsonpath"

result, err := jsonpath.Get("$.store.book[0].title", data)
// result: "Moby Dick"

When working with JSON schemas to validate the structure before querying, the QTool JSON Schema Generator can auto-generate a schema from any JSON sample. And if you need to convert between JSON and YAML before or after querying, the JSON to YAML converter handles that instantly.

Best Practices for JSONPath Queries

1. Use Explicit Paths Over Recursive Descent

Prefer $.store.book[*].price over $..price when you know the structure. Recursive descent is convenient but slower on large documents and can match keys you did not intend if the same key name appears at different levels.

2. Validate JSON Before Querying

Always validate your JSON input before running queries. Invalid JSON causes JSONPath libraries to throw unhelpful errors or return empty results. Use a JSON validator to check for syntax errors first.

3. Handle Empty Results Gracefully

JSONPath returns an empty array when no elements match a query. Always check for empty results in your code rather than assuming the query will always match. This is especially important for filter expressions where the data might not contain any matching elements.

4. Be Aware of Implementation Differences

Despite RFC 9535, older JSONPath libraries may behave differently with edge cases. Test your expressions in the target library before deploying. Pay particular attention to: negative array indices, regex in filters, nested filter expressions, and whitespace handling.

5. Use Bracket Notation for Special Characters

Dot notation only works for simple property names (letters, numbers, underscores). For keys with spaces, dots, hyphens, or unicode characters, use bracket notation: $['my-key'], $['key with spaces'].

6. Combine with JSON Schema for Robustness

If you are writing JSONPath queries against API responses, validate the response against a JSON schema first. This ensures the structure matches your expectations and prevents JSONPath queries from silently returning wrong results due to API changes.

Explore and Validate Your JSON Data

Paste your JSON, view the structure, validate the syntax, and test your queries. All in the browser, all free.

Open QTool JSON Viewer

Frequently Asked Questions

What is JSONPath?

JSONPath is a query language for extracting data from JSON documents, similar to how XPath queries XML. It uses a path syntax starting with $ (the root element) and supports operators like dot notation ($.store.book), bracket notation ($['store']['book']), wildcards (*), recursive descent (..), array slicing ([0:5]), and filter expressions (?(@.price < 10)). JSONPath is standardized in RFC 9535.

What is the difference between JSONPath and jq?

JSONPath is a query language focused on selecting and extracting data from JSON. jq is a full-featured command-line JSON processor that can select, transform, filter, sort, group, and construct new JSON. JSONPath is simpler to learn and available as a library in every major language. jq is more powerful but has a steeper learning curve. Use JSONPath in application code; use jq in shell scripts and pipelines.

How do I filter JSON arrays with JSONPath?

Use filter expressions with the ?() syntax. The @ symbol refers to the current element being evaluated. For example, $.users[?(@.age > 18)] selects all users older than 18. $.products[?(@.price < 50 && @.inStock == true)] selects products under $50 that are in stock. You can use comparison operators (==, !=, <, >) and logical operators (&&, ||) inside filters.

Is JSONPath standardized?

Yes. JSONPath was formalized as RFC 9535 (published February 2024) by the IETF. Before the RFC, implementations varied between languages. The RFC standardizes the syntax, semantics, and expected output for all operators. When choosing a JSONPath library, check whether it conforms to RFC 9535 for consistent cross-platform behavior.

Can I test JSONPath expressions online?

Yes. Paste your JSON into a tool like QTool JSON Viewer and explore the structure visually. You can also validate JSON syntax with the QTool JSON Formatter before writing queries. Browser-based tools process your data client-side, so no data leaves your machine.

Explore 269 Free Developer Tools

JSON Viewer is just the start. QTool has free tools for formatting, validation, conversion, regex, CSS, and much more.

Browse All Free Tools
NT

Christian Bucher

We build free, privacy-first developer tools. Our mission is to make the tools you reach for every day faster, cleaner, and more respectful of your data.

Related Tools

CSS Box Shadow Generator · Free JSON to YAML Converter · Emoji Picker & Search

Related Tools

Free JSON Validator · Visual JSON Editor - Tree View & Raw Editor · Free JSON Schema Validator

Built by Miguel

Need a custom tool or website?

From . Delivered in 24-48h. You own the code.

View Services →