JSONPath Cheat Sheet — Query and Filter JSON Without Code
Complete JSONPath reference with examples. Filter arrays, select nested fields, use wildcards and recursive descent. Copy-paste expressions for real JSON structures.
JSONPath is XPath for JSON. It lets you reach into a JSON document and extract exactly the value you need — whether that’s a single field buried three levels deep, every element in an array that passes a condition, or all values with a particular key anywhere in the document. If you’ve ever pasted JSON into a tool and manually clicked through nested objects to find the value you wanted, JSONPath is the programmatic version of that.
The standard was formalized as RFC 9535 in 2024, settling years of inconsistent implementations. Before that, the original specification by Stefan Göessner (2007) was the de facto reference, but different libraries interpreted edge cases differently. Today, RFC 9535 is the authoritative source, and most modern tools conform to it.
You’ll run into JSONPath in Kubernetes field selectors, AWS Step Functions choice states, Postman test scripts, Terraform data source filters, and dozens of API testing and ETL tools. The same expression syntax works across all of them — learning it once pays off everywhere.
For hands-on exploration while you read, the JSON Viewer lets you paste any JSON structure and copy the path to any node with one click.
The root and dot notation
Every JSONPath expression starts with $, which refers to the root of the document. From there you navigate with dots.
$ → the entire document
$.name → top-level field named "name"
$.address.city → nested field: address object, then city field
$.user.id → nested field: user object, then id field
Dot notation works for keys that are valid identifiers. For keys that contain spaces, hyphens, dots, or other special characters, use bracket notation instead:
$['content-type'] → key with a hyphen
$['@context'] → key starting with @
$['my field'] → key with a space
Bracket and dot notation can be mixed freely:
$.users[0]['first-name']
Arrays
Array elements are addressed by zero-based index inside square brackets:
$.items[0] → first element
$.items[1] → second element
$.items[-1] → last element (RFC 9535 supports negative indexing)
$.items[-2] → second-to-last element
Select multiple specific indexes with a union:
$.items[0,2,4] → elements at index 0, 2, and 4
Slice notation uses a colon — the same style as Python:
$.items[0:3] → elements at index 0, 1, 2 (not including 3)
$.items[2:] → from index 2 to the end
$.items[:3] → first three elements
$.items[::2] → every second element
Use [*] to select all elements:
$.items[*] → all elements in the items array
$.users[*].email → the email field from every user object
Wildcard and recursive descent
The wildcard * matches any key at the current level:
$.user.* → all values directly inside the user object
$.items[*] → all array elements (covered above)
The recursive descent operator .. searches at any depth. This is the most powerful — and most expensive — operator:
$..name → every field named "name" anywhere in the document
$..price → every "price" field, no matter how deeply nested
$..* → every single value in the entire document
Recursive descent is useful for API responses where the structure isn’t fully predictable, or when you need to audit a document for all occurrences of a key. It scans the whole tree, so avoid it on very large documents in performance-sensitive contexts.
Filter expressions
Filter expressions let you select elements based on conditions. The syntax uses ?() with @ referring to the current element:
$.items[?(@.price < 20)]
This returns every object in items where the price field is less than 20.
Comparison operators: ==, !=, <, <=, >, >=
$.items[?(@.status == "active")]
$.users[?(@.age >= 18)]
$.orders[?(@.total != 0)]
Logical operators combine conditions:
$.users[?(@.age >= 18 && @.verified == true)]
$.products[?(@.stock > 0 || @.backorder == true)]
Check for key existence with the @.key pattern alone (no comparison) — RFC 9535 uses an existence test:
$.items[?(@.discount)] → items that have a "discount" field
$.users[?(!@.suspended)] → users that don't have a "suspended" field
String matching varies by implementation. RFC 9535 defines match() and search() functions:
$.users[?(search(@.name, "^Ali"))] → names starting with "Ali"
Quick reference table
| Expression | What it does | Example result |
|---|---|---|
$ | Root of the document | Entire JSON |
$.name | Top-level field | "Alice" |
$.user.city | Nested field | "London" |
$.items[0] | First array element | {...} |
$.items[-1] | Last array element | {...} |
$.items[1:3] | Slice (index 1–2) | [{...}, {...}] |
$.items[*] | All array elements | [{...}, ...] |
$.users[*].id | One field from every object | [1, 2, 3] |
$..name | All name fields at any depth | ["Alice", "Bob"] |
$..* | Every value in the document | All values |
$.items[?(@.price < 10)] | Filter by condition | Matching items |
$['content-type'] | Key with special characters | "application/json" |
Where JSONPath is used in practice
Kubernetes uses a subset of JSONPath in kubectl for --output jsonpath queries. You can extract specific fields from resource manifests:
kubectl get pods -o jsonpath='{.items[*].metadata.name}'
AWS Step Functions uses JSONPath for input/output processing in state machines. Choice states compare input fields: $.order.status == "APPROVED".
AWS EventBridge rule patterns use JSONPath-style conditions to filter events before invoking targets, reducing noise and Lambda invocations.
Postman test scripts use JSONPath to extract values from response bodies:
const id = pm.response.json().data[0].id;
(Postman also has its own pm.response.jsonBody() helpers, but raw JSONPath expressions work too.)
Terraform data sources support JSONPath-like expressions when filtering results from external APIs via the http provider.
JavaScript libraries: jsonpath-plus is the most widely used implementation. It extends the original Göessner spec with additional features. @astronic/jsonpath is a newer RFC 9535-compliant option.
import { JSONPath } from 'jsonpath-plus';
const result = JSONPath({ path: '$.users[?(@.active)].name', json: data });
Python: The jsonpath-ng library provides RFC 9535-compatible parsing:
from jsonpath_ng import parse
matches = parse('$.items[?(@.price < 20)]').find(data)
values = [m.value for m in matches]
JSONPath vs jq
JSONPath and jq serve similar purposes — both let you query and filter JSON from the command line or in scripts — but they’re different tools with different trade-offs.
JSONPath is simpler, built into many tools without installation, and designed to be embedded in configuration files (Kubernetes manifests, EventBridge rules, Step Functions states). The syntax is compact enough to write in a YAML field without escaping nightmares.
jq is a full query language with functions, variables, string interpolation, reduce, @base64 encoding, and more. It’s considerably more powerful for data transformation. But it requires a separate installation, has its own syntax that takes time to learn, and produces different output formatting by default.
For read-only extraction and filtering — especially in tools that support JSONPath natively — JSONPath is the right choice. For complex transformations on the command line, jq wins.
If you’re already working in a JSON viewer, you don’t need either: the JSON Viewer shows the structure visually and lets you click any value to copy its JSONPath expression directly — no memorization required.
The expressions that actually come up
In practice, about 80% of JSONPath usage is covered by four patterns:
- Direct field access —
$.user.email— the most common case - All items in a list —
$.items[*].id— extracting one field from every object in an array - Filter by condition —
$.orders[?(@.status == "shipped")]— the second most useful pattern - Recursive lookup —
$..error— finding all error fields in a deeply nested API response
The recursive descent operator looks impressive but is used sparingly in production. Direct paths are faster, easier to maintain, and make schema changes obvious when they break.
The quick reference table above covers the full syntax. Keep it open while you build your next Kubernetes selector, Postman assertion, or EventBridge rule — and use the JSON Viewer when you want the path built for you.
Written by Mian Ali Khalid. Last updated 2026-05-12.
Related posts
- JSON Crack Alternatives — Free JSON Graph and Tree Viewers — Looking for a JSON Crack alternative? Compare free JSON graph viewers and tree v…
- JSON Editor Online — Edit, Fix, and Validate JSON in the Browser — Free online JSON editor — modify keys, values, and structure directly. Syntax hi…
- JSON Viewer Online — Read and Navigate Any JSON Structure — Free online JSON viewer — paste any JSON and explore it as a collapsible tree. S…
- JSON Formatter — Why Formatting JSON Matters and How It Works — A JSON formatter takes compact, hard-to-read JSON and adds whitespace and indent…
- JSON Parse Errors — SyntaxError, Common Causes, and Safe Parsing — JSON.parse throws SyntaxError for any malformed input. Learn the most common JSO…
Written by Mian Ali Khalid. Part of the Data & Format pillar.