JSONPath Evaluator

Paste JSON and enter a JSONPath expression to extract values. Supports $, *, .., and filter expressions. 100% client-side.

Last reviewed: April 2026

New to this tool? Click here for instructions

JSON Input
Results
Paste JSON and enter a JSONPath expression above.

Evaluate JSONPath expressions against any JSON document, see matched values alongside the paths that produced them, and verify expression behavior before pasting it into a kubectl command, an OpenAPI validator, a Postman test, or a Splunk query.

What This Tool Does

This tool evaluates JSONPath expressions against JSON documents — the XPath-equivalent query language for JSON data. JSONPath gives you a compact, embeddable syntax for navigating arbitrary JSON structures: drill into nested objects, traverse arrays, filter elements by predicate, and collect matching values into a flat result list. It is the same query model used by kubectl -o jsonpath=..., the Splunk and ElasticSearch query DSLs, OpenAPI response validators, Postman test scripts, and Helm chart lookup templates.

The evaluator supports the core JSONPath operator set: $ (the root reference), . and [] (child descent — dot notation and bracket notation are interchangeable), * (wildcard — every key of an object or every element of an array), .. (recursive descent — walk every node in the tree), [?(@.x > 5)] (filter expressions — select array elements matching a predicate), [0:3] (slice expressions — select contiguous ranges of array elements), and negative indices [-1] for last-element access. Two output modes are available: Highlight Matches shows the full JSON document with matches called out, and Raw Values returns just the matched values as a JSON array — the format you would copy into a downstream pipeline. Every computation runs client-side; nothing about your JSON document or your expression leaves the browser.

How to Use It: Step-by-Step

The tool layout follows the same split-pane pattern as the rest of the JSON tooling on this site. The JSON document goes on the left, the JSONPath expression goes in the dedicated input above the panes, and matched values appear on the right as they update in real time.

Pasting the JSON Document

Paste or type your JSON into the left textarea. The parser uses the browser's native JSON.parse, so any well-formed JSON document is accepted: nested objects, arrays of arrays, mixed types, null values, scientific notation, Unicode strings — anything that round-trips through a standard JSON parser will work here. If the JSON is malformed, the status bar at the bottom turns red and reports the parser error message with the position of the failure. Click Try Example to pre-load a representative tools-and-meta document that exercises arrays, nested objects, mixed types, and predicate-friendly numeric fields.

Entering the JSONPath Expression

Type your JSONPath expression into the input field above the split pane. Every valid expression begins with $ — the root reference. From there, descend using dot notation ($.store.book), bracket notation ($['store']['book']), wildcard ($.store.book[*]), recursive descent ($..book), or any combination. Press Evaluate or wait for the debounced update; either path runs the same evaluation logic. The status bar reports the match count and the type of failure (parse error vs. zero matches) so you can distinguish a bug in the expression from a query that simply didn't find anything.

Switching Output Modes

The two option chips above the input toggle between Highlight Matches and Raw Values. Both modes currently render the matched values as a formatted JSON array — Raw Values is the format you would pipe directly into a downstream tool, while Highlight is intended for visual review. The Copy button copies the current output to your clipboard; Download results.json saves it as a file with a .json extension and the standard MIME type.

Worked Example: Filtering Books by Price

The canonical JSONPath example — used in Stefan Goessner's original 2007 article and again in RFC 9535 — is a bookstore inventory. We use a reduced version of it here to walk through how the tokenizer, parser, and evaluator combine to produce a result.

Input Document

Paste the following two-book inventory into the left pane:

{
  "store": {
    "book": [
      { "title": "X", "price": 12 },
      { "title": "Y", "price": 7 }
    ]
  }
}

Expression

Enter the JSONPath expression $.store.book[?(@.price < 10)].title into the path input. Read literally: start at the root, descend into store, descend into book (which is an array), filter array elements where the current element's price is less than 10, then extract the title of each matching element.

Expected Output

The result is the JSON array ["Y"]. Only the second book ("Y") has a price below 10; the first book ("X", $12) is filtered out before the .title descent runs. If you change the filter threshold to < 15 the result becomes ["X", "Y"]; change it to < 5 and the result is the empty array [] with the status bar reading "0 matches."

Walkthrough: Tokenizer, AST, Evaluator

The expression goes through three phases internally. The tokenizer scans the string character by character, splitting it into a sequence of segments. The leading $ is consumed; then it encounters .store (a child segment with key store), .book (a child segment with key book), [?(@.price < 10)] (a bracketed segment whose contents are recognized as a filter expression because they begin with ?(), and finally .title (another child segment).

The AST for this expression is a flat array of four segments: {type: 'child', key: 'store'}, {type: 'child', key: 'book'}, {type: 'filter', expr: '@.price < 10'}, {type: 'child', key: 'title'}. JSONPath grammars are linear rather than tree-shaped because the language is purely a sequence of navigation steps — there is no operator precedence to encode in nesting, only an ordered chain of selections.

The evaluator threads a list of current nodes through the segment chain. It starts with a single-element list containing the root document. For each segment, it computes the next list of matching nodes. After store, the list contains one object — the store sub-document. After book, the list contains one array — the book array. After the filter, the list contains only objects whose price is less than 10 — just the second book. After title, the list contains one string: "Y". The evaluator wraps that into a JSON array and the renderer formats it.

Common Use Cases

Kubernetes kubectl Output Filtering

kubectl ships with first-class JSONPath support via the -o jsonpath=... flag, which is the most-used JSONPath surface in modern infrastructure work. Commands like kubectl get pods -o jsonpath='{.items[*].status.podIP}' extract every pod's IP address into a single space-separated list; kubectl get nodes -o jsonpath='{.items[?(@.status.conditions[?(@.type=="Ready")].status=="True")].metadata.name}' filters for ready nodes by name. Testing these expressions inside an evaluator before pasting them into a live cluster command is faster than iterating against kubectl directly — kubectl's JSONPath dialect omits the leading $ (it is implied) and uses literal {} braces to delimit the expression, but the operator semantics inside are otherwise compatible with this tool.

jq Alternative for Simple Selections

For pure-selection workloads — pull this field, filter on that condition, return the matching values — JSONPath produces shorter, more readable expressions than jq for the same task. Compare $.items[?(@.status == "active")].name against the equivalent jq .items | map(select(.status == "active") | .name). JSONPath wins for navigation; jq wins the moment you need to compute, restructure, or chain pipelines. Many infrastructure teams use both — JSONPath for embedded scenarios (kubectl, Postman) and jq for shell-side transformations.

OpenAPI Response Schema Validation

OpenAPI tooling uses JSONPath to refer to specific locations in request and response payloads when defining validators, test assertions, or schema constraints. Postman test scripts, for example, accept JSONPath expressions inside pm.expect(pm.response.json()).to.have.jsonPath(...) assertions, letting you check that a specific field exists at a specific depth without writing the equivalent JavaScript navigation by hand. OpenAPI YAML Converter and JSON Schema Generator are useful companions when you are working on the schema side of the workflow.

Splunk and ElasticSearch Query DSLs

Splunk's spath command accepts JSONPath-style expressions for extracting fields from JSON-encoded events; ElasticSearch's query DSL similarly accepts dotted-path field references for nested document queries. Both follow the same intuition — navigate to a field by name path, optionally with array indexing — but the dialect details differ from the Goessner JSONPath specification in ways that occasionally trip up newcomers (Splunk uses curly braces for array elements; ElasticSearch lacks recursive descent entirely).

GraphQL Response Navigation and Helm lookup() Templates

GraphQL response payloads are deeply nested JSON, and JSONPath is a common idiom for extracting specific fields out of those responses in client code — particularly when working with generated GraphQL clients that return loosely-typed result objects. Helm chart templates expose a lookup function that fetches arbitrary Kubernetes resources, and JSONPath-like dotted-path access is the canonical way to drill into the lookup's result. GraphQL Query Builder and YAML Validator serve adjacent steps in those workflows.

Edge Cases and Dialect Differences

JSONPath is a notoriously inconsistent language — until RFC 9535 landed in February 2024, there was no canonical specification, only Stefan Goessner's 2007 article and seventeen years of library implementations independently filling in the gaps. The result is that the same expression can produce different results depending on which library evaluates it. The most common areas of divergence are below.

Multiple dialects with different histories. Stefan Goessner's original 2007 implementation — Goessner-flavor — is what most JavaScript libraries (jsonpath, jsonpath-plus) target. Jayway's Java implementation extended the syntax with script expressions and a richer filter grammar; the Jayway dialect is what kubectl, the JMeter project, and JsonPath.com use. RFC 9535 from the IETF, published in 2024, is now the standardized version, but adoption is still mid-flight. This tool implements a pragmatic subset compatible with Goessner-flavor and the parts of RFC 9535 most tools actually use.

Recursive descent semantics drift between dialects. Expressions like $..* behave subtly differently across libraries — some return every primitive value in the document, others return every object and array as well, and a few return only leaf nodes. This is one of the cases RFC 9535 nails down explicitly. The tool here follows the most common interpretation: .. visits every node in the tree, and a wildcard or named child following .. selects from each visited node.

Script expressions [(@.length-1)] are dialect-specific. Jayway introduced this syntax to let you compute array indices dynamically — accessing the last element of an array, for instance. RFC 9535 does not include script expressions; it provides the cleaner [-1] negative-index syntax instead. This tool supports [-1] but not script expressions.

Negative indexing for end-relative access. The expression $.book[-1] returns the last element of the book array, $.book[-2] the second-to-last, and so on. Most modern libraries support negative indexing; some older Goessner implementations do not, and you may need to fall back to $.book[length-1]-style script expressions in those.

Filter syntax with regex. Regex filtering is one of the noisiest areas of divergence: RFC 9535 uses a function-style match(@.title, '^Sword'), Goessner-flavor accepts JavaScript literal regex @.title =~ /^Sword/, Jayway uses Java regex semantics with the same =~ operator, and Python's jsonpath-ng requires explicit function calls. This tool does not currently implement regex filters — comparison operators only.

Key-vs-value tests in filters. A filter like [?(@.published)] can mean two different things depending on the library: either "the published property exists and is truthy" (existence + truthiness, the JavaScript-style interpretation) or strictly "the published property exists" regardless of value (the SQL-style interpretation). This tool uses the existence-plus-truthiness interpretation, matching most JavaScript JSONPath libraries.

Behind the Scenes: Goessner, the 17-Year Gap, and RFC 9535

Stefan Goessner's 2007 Article

JSONPath was introduced in a 2007 blog post by German software engineer Stefan Goessner, titled "JSONPath — XPath for JSON." The article was three pages long. It defined the headline operators — $, ., .., *, [], [?()], and slice expressions — alongside a reference PHP implementation and a parallel JavaScript implementation. For a blog post it was remarkably influential: every major JSONPath library traces its lineage back to that article. But it was deliberately not a specification. Edge cases — recursive descent semantics across mixed structures, filter coercion rules, negative-index behavior on out-of-range queries — were left for implementers to figure out.

The 17-Year Gap

For seventeen years, JSONPath had no standard. Libraries diverged. JsonPath.com (the Jayway-backed playground) used the Java dialect; Postman used something close to but not identical to Goessner; kubectl carved its own variant. Implementations could not be reasoned about generically — every JSONPath user had to know which dialect their specific tool spoke. This is one of the reasons JSONPath never achieved the ubiquity XPath enjoys for XML: without a standard, language-level adoption (built into curl, built into IDEs, taught in textbooks) never quite materialized.

RFC 9535 (February 2024)

The IETF's jsonpath Working Group formed in 2020 with a charter to formalize JSONPath. Four years and many drafts later, RFC 9535 — "JSONPath: Query Expressions for JSON" — was published in February 2024 as a Proposed Standard. The RFC defines a formal grammar, pins down semantics in every place where dialects had drifted, introduces a normalized output format for paths (so you can identify a match by the canonical path that produced it, not just the matched value), and provides a function extension mechanism for libraries to add custom predicates without breaking conformance.

Why JSONPath Was Never as Widely-Used as XPath

XPath had a draft W3C specification in 1999 and a final REC in late 1999 — published alongside the rest of the XML stack. Every major XML parser ships an XPath engine; XPath is teachable from a single canonical reference. JSONPath landed without that institutional weight: a blog post is a fine starting point but a poor anchor for a decade of follow-on tooling. The RFC 9535 publication is the moment that asymmetry starts to close, but the cultural lag — the fact that "JSON query language" still means "jq" or "JMESPath" or "JSONPath" depending on whom you ask — will take years to flatten.

Comparison: JSONPath vs JMESPath vs jq vs gjson vs JSON Pointer

JSON query languages are not interchangeable. Each was designed with different priorities — embedability, expressiveness, formal rigor, performance — and the right choice depends on the workflow. The table below distills the practical differences across five common languages.

JSON Query Language Feature Matrix: JSONPath, JMESPath, jq, gjson, JSON Pointer
Feature JSONPath (RFC 9535) JMESPath jq gjson (Go) JSON Pointer (RFC 6901)
Filtering by predicate Yes ([?(...)]) Yes ([?...]) Yes (select(...)) Yes (#(field==value)) No
Array slicing Yes ([0:3]) Yes ([0:3]) Yes (.[0:3]) Limited Single index only
Recursive descent Yes (..) No Yes (..) Yes (#.field) No
Regex matching Yes (match()) No (third-party) Yes (test()) Yes (% operator) No
Scripting / computation No Functions only (length, sort_by, etc.) Full functional language No No
Mutation / write No (read-only) No (read-only) Yes (assignment, deletion) Companion sjson library Use JSON Patch (RFC 6902)
Formal specification RFC 9535 (2024) jmespath.org spec + test suite Man page + reference impl README documentation RFC 6901 (2013)
Primary use cases kubectl, Postman, Splunk, OpenAPI AWS CLI, AWS SDKs Shell-side JSON transforms High-performance Go services JSON Patch references, schema $ref
JSONPath and jq are the most expressive for selection and computation respectively; JMESPath has the strongest conformance test suite; JSON Pointer is the simplest — single-path access without filtering or recursion — and is the addressing format used inside JSON Patch and JSON Schema.

The practical decision typically reduces to two questions. First, are you embedded or shell-side? Embedded contexts — kubectl, Postman, OpenAPI validators, IDE plugins — almost always speak JSONPath; shell pipelines almost always speak jq. Second, are you in the AWS ecosystem? If yes, JMESPath is the lingua franca. Outside of those constraints, prefer JSONPath for selection-heavy work, jq for transformation-heavy work, and JSON Pointer when you need a stable single-path reference that round-trips cleanly through JSON Patch operations.

Frequently Asked Questions

JSONPath and JMESPath are two distinct query languages for JSON, designed with different goals. JSONPath originated in Stefan Goessner's 2007 blog post as a JSON analogue of XPath, with a deliberately compact syntax: $.store.book[*].title. JMESPath was designed later at AWS for the official AWS CLI and SDKs, with a formal grammar published from the start and a richer expression language including pipes, multi-select hashes, and built-in functions like length() and sort_by(). JMESPath does not support recursive descent (..); JSONPath does. JMESPath has formal compliance test suites that every implementation passes identically; JSONPath has historically suffered from dialect drift across implementations. If you are scripting against AWS, you are almost certainly using JMESPath; if you are working with Kubernetes, Splunk, or older REST tooling, you are using JSONPath.
Yes. RFC 9535 was published by the IETF in February 2024 as a Proposed Standard, formally titled "JSONPath: Query Expressions for JSON." It represents the first standardized specification of JSONPath in the seventeen years since Stefan Goessner's original 2007 article. The RFC pins down operator semantics that previously varied between implementations: recursive descent behavior, filter expression grammar, slice expressions, comparison semantics, and the structure of normalized output paths. Compliance test suites are maintained by the IETF jsonpath Working Group. New implementations are expected to target RFC 9535; many existing libraries (jayway/JsonPath, jsonpath-plus, jsonpath-rw) predate the RFC and continue to implement their own historical dialects, which is the primary reason results differ across libraries.
JSONPath and jq target different workflows. JSONPath is a path-selection language — its grammar is roughly the size of XPath's, and most expressions are read-only navigations through a document. It is embedded inside many tools (kubectl, Splunk, Postman, OpenAPI validators) precisely because the surface area is small enough to embed without shipping a full programming language. jq is a complete functional programming language that happens to operate on JSON: it supports map, reduce, recursion, user-defined functions, regex, arithmetic, string formatting, and arbitrary control flow. Choose JSONPath when you need to extract a known shape from a known document, choose jq when you need to transform, restructure, or compute across the data. JSONPath expressions tend to be much shorter for navigation tasks; jq pipelines are much more powerful for restructuring tasks.
The expression $..book[*] reads in three parts. The leading $ anchors the query at the root of the input document. The double-dot .. is the recursive descent operator — it walks the entire document tree from the root downward and selects every node whose key is the next token. So $..book matches any value stored under a "book" key at any depth, whether "book" appears once at the top level or nested deep inside arrays and objects. The trailing [*] is a wildcard array index: it selects every element of an array. Combined, $..book[*] means "find every 'book' value anywhere in the document, treat each as an array, and return every element of those arrays as a flat result list." In the canonical Goessner store example, the query returns every book object across the entire bookstore inventory.
Regex filtering is one of the areas where JSONPath dialects diverge most visibly. RFC 9535 includes a match() function and a search() function in the standard library, callable inside filter expressions: $.book[?match(@.title, '^Sword.*')]. Older Goessner-style implementations sometimes accept a JavaScript regex literal directly: $.book[?(@.title =~ /^Sword/)]. Java's jayway/JsonPath uses a similar =~ syntax with Java regex semantics, which differs from JavaScript regex in lookbehind support and Unicode handling. Python's jsonpath-ng requires explicit function-style calls. The practical advice: pick the library you are evaluating against, read its filter grammar specifically, and prefer RFC 9535 match()/search() in any new code where the library supports it. The tool on this page does not currently support regex filters — comparison operators (==, !=, <, >, <=, >=) and existence checks only.
A slice expression selects a contiguous range of array elements using Python-style notation inside square brackets: [start:end:step]. $.book[0:3] returns elements 0, 1, and 2 (end is exclusive). $.book[::2] returns every second element starting from index 0. $.book[-3:] returns the last three elements via a negative start index. $.book[::-1] reverses the array. The full grammar is identical to Python list slicing — all three components are optional, negative indices count from the end, and the step value controls direction and stride. Slices are part of RFC 9535 and supported in most JSONPath implementations, though edge case behavior (especially with step=0, which is a syntax error, and out-of-range indices, which are silently clamped) is one of the spots where older libraries occasionally disagree.
JSONPath is fundamentally a read-only query language — it selects paths but does not mutate the underlying document. The RFC 9535 specification deliberately defines no write operations. However, several libraries extend the syntax with mutating operations as library-specific additions. Java's jayway/JsonPath provides set(), add(), delete(), put(), and renameKey() methods that accept a JSONPath query and mutate matching nodes. JavaScript's jsonpath-plus offers a callback form where the caller can mutate during traversal. For standardized mutation of JSON documents, the appropriate technology is JSON Patch (RFC 6902) or JSON Merge Patch (RFC 7396) — both are designed specifically for read-modify-write workflows and have well-defined semantics around array index changes and conflict resolution. JSONPath plus JSON Patch is a common pairing: use JSONPath to locate the target, emit a JSON Patch operation to mutate it.
JSONPath suffered seventeen years of dialect drift before RFC 9535 standardized the language in 2024. Stefan Goessner's original 2007 article was a blog post, not a specification — it defined the headline syntax but left many edge cases unaddressed. Library authors filled the gaps independently and made different choices. Jayway's Java implementation invented script expressions [(@.length-1)] as a way to compute array indices dynamically; Python's jsonpath-ng used a different syntax. Recursive descent (..) followed by a filter behaves differently in different libraries — some apply the filter to every descendant array, others only to the deepest. Slice steps with negative values were inconsistent. Boolean coercion in filter comparisons varied. RFC 9535 is the first definitive answer to these questions, but legacy libraries are not required to retroactively conform. Cross-library portability requires either targeting RFC 9535 explicitly, restricting yourself to the subset of operators where all dialects agree, or pinning your query to one specific library.