NV ToolkitFormat · Validate · Convert

JSON Tools

JSONPath & JMESPath Tester — Query JSON Online

Paste a document, write an expression, and see exactly what it selects. Two dialects in one page — JSONPath for recursive descent and filters, JMESPath for projections and reshaping — evaluated entirely in your browser.

In short

Test JSONPath and JMESPath expressions against your own JSON online. Filters, wildcards, recursive descent and projections evaluated live in your browser.

By NaveenKumar T · Updated

Learn: JSON Crack Alternative Without Signup: Viewing JSON as a Tree

  • JSONPath (jsonpath-plus) and JMESPath in one tool
  • Recursive descent, wildcards and filter expressions
  • JMESPath projections, multiselect and functions

Runs entirely in your browser — nothing you paste or open here is uploaded, logged, or stored.How we handle data →

Why this tool

Get the expression right before it reaches production

A path expression is code that lives in a config file, a CI step or an integration platform, where a typo fails silently and returns nothing. Testing it against a real payload takes seconds here and saves a debugging session there.

Two dialects, one page

JSONPath is what Kubernetes, Postman and most log tooling speak. JMESPath is what the AWS CLI, Ansible and Azure CLI speak. Switch dialects without leaving the page and compare what each one selects.

Real filters and projections

Recursive descent ($..price), wildcards, array slices, filter expressions ($[?(@.qty>1)]) and JMESPath multiselect hashes all evaluate against your own document, not a canned demo.

Honest, readable results

JSONPath results are always wrapped in an array, so one match and ten matches look the same and your consuming code never has to special-case a single hit. JMESPath returns its result verbatim.

Your payload stays yours

Both engines are downloaded and run in your browser. Production responses, tokens and customer records are never uploaded, so you can test against the real thing instead of a redacted copy.

Learn more

Query a JSON document without writing a program

Sooner or later every JSON document turns into a question. Which line items have a quantity above one? What are all the prices, wherever they appear? What does this API return once you strip it down to the three fields you actually need? Writing a script to answer that is possible but wasteful, and eyeballing a 4,000-line response is worse. A path expression answers it in one line — the trick is getting the line right, which is what this page is for.

It runs two dialects. JSONPath, evaluated by jsonpath-plus, is the XPath-inspired notation you already meet in Postman tests, log pipelines, API gateways and a hundred config formats: it starts at the root, walks down through keys and array indices, and can search recursively for a key at any depth. JMESPath, the language behind the AWS CLI's --query, Ansible's json_query and the Azure CLI, is a small expression language: it evaluates to exactly one value, and it can reshape what it selects into a new object.

Both evaluate against the document in the large pane, with the expression in the smaller pane below it, the moment you press Run query. Results come back as pretty-printed JSON at your chosen indentation, ready to copy into a test, a fixture or a ticket. If the expression will not parse, the engine's own message is shown verbatim rather than being rewritten into something vaguer — library messages are terse but they are precise about where the parser gave up.

Everything runs locally. The engines are fetched to your browser and evaluated there, so you can test against a genuine production response — tokens, customer names and all — without it being uploaded anywhere. When you need to understand the structure first, open the payload in the JSON Viewer or tidy it in the JSON Formatter, then come back and write the expression against the real shape.

JSONPath vs JMESPath, task by task

The two dialects overlap for simple lookups and diverge sharply once you ask for anything clever. The table below maps the tasks that come up daily onto both notations, using the sample order document loaded by the Sample button — an order with a customer object and an items array.

Three differences do most of the damage when you switch between them. Literals: JMESPath requires backticks around numbers and JSON literals inside filters, so [?qty>`1`] is right and [?qty>1] is a parse error, while JSONPath writes it plainly as [?(@.qty>1)]. Roots: JSONPath expressions conventionally begin with $, JMESPath expressions simply begin with the first key. And depth: JSONPath's .. searches every level for a key, which JMESPath deliberately has no equivalent for — if you do not know where a value lives, JSONPath is the only one of the two that can find it.

The other asymmetry is direction. JSONPath only ever gives you back nodes that already exist in the document, flattened into a list. JMESPath can construct: rename keys, pick a subset, build a hash per element, apply functions such as length(), sort_by() and join(). If your goal is "find it", start with JSONPath; if your goal is "give me this shape", start with JMESPath.

The same task in both dialects
TaskJSONPathJMESPath
A top-level field$.orderIdorderId
A nested field$.customer.namecustomer.name
First array element$.items[0]items[0]
Last array element$.items[-1:]items[-1]
One field from every element$.items[*].skuitems[*].sku
First two elements (slice)$.items[0:2]items[0:2]
Every occurrence of a key, any depth$..pricenot supported — name the path
Filter by a number$.items[?(@.qty>1)]items[?qty>`1`]
Filter by a string$.items[?(@.sku=='MUG-01')]items[?sku=='MUG-01']
Reshape each elementnot supported — select fields separatelyitems[*].{sku: sku, qty: qty}
Count the elements$.items.lengthlength(items)
Sort by a fieldnot supportedsort_by(items, &qty)

Worked example: the same question, both ways

The Sample button loads the order below: a couple of top-level fields, a customer object, and two line items with a SKU, a quantity and a price. It is deliberately small enough to check the answers by eye, and shaped like the payloads that actually cause trouble — an array of objects nested inside a document.

Ask JSONPath for the SKUs of every line item ordered more than once — $.items[?(@.qty>1)].sku — and it filters the array, then pulls one field from each survivor. The result is a flat array of matches, wrapped as always, so a second qualifying item would simply appear as a second element.

Ask JMESPath the same question but demand a shape — items[?qty>`1`].{sku: sku, qty: qty} — and it filters with backticked literals, then builds a fresh object per surviving element containing only the keys you named. Note that the quantity comes along for the ride, which JSONPath cannot do in one expression: it would have to return the whole object and let you throw away the parts you did not want.

That is the practical distinction in one example. JSONPath extracts values that exist; JMESPath produces the structure you asked for. Both answers are correct; which one you want depends on whether the next step is a human reading it or a program consuming it.

Data
{
  "orderId": "ORD-10428",
  "status": "paid",
  "total": 48.5,
  "customer": {
    "name": "Ada Lovelace",
    "email": "ada@example.com"
  },
  "items": [
    {
      "sku": "TS-BLK-M",
      "qty": 2,
      "price": 18
    },
    {
      "sku": "MUG-01",
      "qty": 1,
      "price": 12.5
    }
  ]
}
JSONPath — $.items[?(@.qty>1)].sku
[
  "TS-BLK-M"
]
JMESPath — items[?qty>`1`].{sku: sku, qty: qty}
[
  {
    "sku": "TS-BLK-M",
    "qty": 2
  }
]

Help

Frequently asked questions

Everything you need to know about the JSONPath Tester.

01What is the difference between JSONPath and JMESPath?

They solve the same problem with different philosophies. JSONPath, modelled on XPath, is a selector: expressions start at the root ($), walk downwards, and return a flat list of every node that matched. It is strongest at searching — $..price finds every price anywhere in the document, at any depth, without you knowing the structure. JMESPath is an expression language: it evaluates to a single value, which can be a projection, a filtered list, or a completely reshaped object built with a multiselect hash. It cannot search blindly for a key at unknown depth, but it can restructure what it selects. Rule of thumb: reach for JSONPath when you are exploring or extracting, and JMESPath when you are transforming output or scripting a CLI.

02Why is the JSONPath result always an array?

Because a JSONPath expression describes a set of matches, not a single value, and the size of that set depends on the data. $.customer.name looks like it must return one string, but change the document and the same expression could match nothing at all. Wrapping the result means the shape of the output never depends on the data: no match is [], one match is a one-element array, ten matches is a ten-element array, and code that consumes the result can always iterate. If you specifically want the unwrapped single value, use the JMESPath dialect instead — customer.name returns "Ada Lovelace", and an expression that matches nothing returns null.

03How do I write a filter expression?

In JSONPath, a filter is [?(...)] where @ stands for the element being tested: $.items[?(@.qty>1)] keeps the line items with a quantity above one, and $..[?(@.price<20)] applies the same test at every depth. You can combine tests with && and ||, compare strings with ==, and test for a key's presence by naming it — $.items[?(@.discount)]. In JMESPath the equivalent is [?qty>`1`], and the difference matters: literal numbers inside a JMESPath filter must be wrapped in backticks, so [?qty>1] is a syntax error while [?qty>`1`] works. JMESPath string literals use single quotes: [?status=='paid'].

04How do I return only some fields from each object?

That is JMESPath's multiselect hash, and it is the main reason to prefer that dialect. items[*].{sku: sku, qty: qty} returns each line item reduced to two keys, in the order you wrote them, and you can rename as you go: items[*].{code: sku, count: qty}. Combine it with a filter to reshape a subset: items[?qty>`1`].{sku: sku, qty: qty}. JSONPath has no equivalent — it can select the objects or select one field across all of them ($.items[*].sku), but it cannot build a new object shape, because every result it returns is a node that already exists in the document.

05Why does my expression return an empty array or null?

Almost always a name or a level, not a bug in the engine. Check the spelling and case of every key (JSON keys are case-sensitive), check whether the property sits one level deeper than you assumed — items[*].sku fails if items is actually data.items — and check whether you are indexing an object as if it were an array. If you are unsure of the structure, expand the document as a tree in the [JSON Viewer](/json-viewer) first. For JSONPath specifically, an empty result is [] rather than an error, because "matched nothing" is a legitimate answer; for JMESPath it is null. A genuinely malformed expression reports the library's own parse error instead.

06Are these the same expressions the AWS CLI and kubectl accept?

For JMESPath, yes — the AWS CLI's --query flag, Ansible's json_query filter and the Azure CLI's --query flag all use JMESPath, and the expression you test here is the one you paste there (mind your shell's quoting, which is usually where a working expression breaks). For JSONPath, mostly. There is no single normative specification, so implementations differ at the edges: kubectl's -o jsonpath uses its own Go implementation with braces and a range construct, Jayway (the JVM implementation used by Rest Assured and many API gateways) has its own function set, and this page runs jsonpath-plus. Plain paths, wildcards, slices and recursive descent behave identically everywhere; script and filter expressions are where dialects diverge, so verify anything exotic against your target runtime.

Keep working

Related tools

Learn the format

Related guides

All guides →