Comparison guide
JSONPath vs jq: Which Query Language to Use
JSONPath vs jq compared on syntax, speed, learning curve, and use cases. Concrete examples and clear picks for filtering, reshaping, and ad-hoc inspection.
You have a JSON blob and a question — "give me every admin user", "rename every key", "sum the quantities". JSONPath and jq are the two most common ways to ask. They look similar at a glance, but they are not interchangeable: one is a selection language, the other is a full transformation pipeline. Picking the right one saves you hours.
Run either against your data in the JSON query tool — both engines are available side-by-side — or read on for the structural differences and concrete recommendations.
Quick answer
Use JSONPath when you only need to select values by path. Use jq when you need to transform, filter on computed conditions, build new objects, or join across collections. JSONPath is the smaller, simpler tool; jq is the Swiss Army knife with a steeper learning curve.
Comparison at a glance
| Criterion | JSONPath | jq |
|---|---|---|
| Type | Selection language | Functional transformation language |
| Syntax style | XPath-like ($.users[*].name) |
Pipeline with filters (.users[].name) |
| Selection | Yes | Yes |
| Transformation | No | Yes |
| Arithmetic | No | Yes |
| Conditionals | Filter expressions only | Full if/then/else, ternary, etc. |
| Variables | No | Yes (as $var) |
| Recursive descent | ..key |
.. then .key? |
| Output shape | Same as input subset | Arbitrary |
| Standardization | RFC 9535 (2024) | jq-lang spec |
| Learning curve | An afternoon | A few days |
JSONPath: simple, path-based selection
Syntax basics
JSONPath uses $ for the root, .key or ['key'] for child access, [*] for
all array elements, and [?(@.field == 'value')] for filter predicates.
{
"users": [
{ "id": "u_001", "name": "Otter", "role": "admin" },
{ "id": "u_002", "name": "Hawk", "role": "viewer" },
{ "id": "u_003", "name": "Lynx", "role": "admin" }
]
}
Get every admin's name:
$.users[?(@.role == 'admin')].name
Result:
["Otter", "Lynx"]
Strengths
- One-page mental model. If you know XPath or CSS selectors, you already know JSONPath.
- Predictable output. The result is always a subset of the input — no surprise restructuring.
- Lightweight. A pure-JS implementation is a few kilobytes.
- Now standardized. RFC 9535 (February 2024) finally codified the syntax differences between popular JSONPath implementations.
Limits
- No transformation. You can't rename keys, compute new fields, or change the output shape. The best you can do is select a different subtree.
- No arithmetic. Filters compare to literals; you can't say "where total > average".
- Filter operators are bare-bones. Equality, ordering, regex match — that's it.
jq: a small language for reshaping JSON
Syntax basics
jq is a pipeline. Each filter takes a value, produces a value (or multiple
values), and | chains them. . is the identity; .users[] iterates an array;
select(predicate) keeps elements; {a, b} builds a new object.
Same data, same question — every admin's name:
.users[] | select(.role == "admin") | .name
Result (one per output line, jq emits a stream):
"Otter"
"Lynx"
Where jq shines
Reshape into a new object:
.users
| map(select(.role == "admin"))
| map({ id: .id, displayName: .name })
[
{ "id": "u_001", "displayName": "Otter" },
{ "id": "u_003", "displayName": "Lynx" }
]
Group orders by customer and sum their totals:
group_by(.customer)
| map({ customer: .[0].customer, total: map(.amount) | add })
These are not exotic asks — they show up in any real data-cleaning script. JSONPath cannot do them at all.
Limits
- Learning curve. The pipeline metaphor and recursive operators (
..,[]) take a few sessions to internalize. - Error messages are terse. A typo in a filter prints a one-line error that doesn't point at the offending character.
- Binary install. jq ships as a C program; for browsers, you need the WebAssembly build (which is what JSONZen's query tool uses).
A note on JMESPath
JMESPath is the third option people consider — it sits between JSONPath and jq. It has more selection power than JSONPath (projections, multi-select hashes) but less transformation power than jq. AWS uses it heavily in CLI tools. If your work lives inside the AWS ecosystem and you don't need transformations, JMESPath is reasonable; otherwise stick with the two above for portability.
When to use which
Use JSONPath when
- You need to extract a single field or filtered subset, nothing else.
- You're embedding queries in config (Kubernetes, OPA, Jaeger) where users write paths but should not write code.
- You want a one-line query that anyone reading the script can understand.
Use jq when
- You're reshaping or aggregating data, not just selecting.
- You're scripting a CLI pipeline that processes JSON.
- You want conditionals, arithmetic, or variables.
- You'll write this query once and run it on every payload from now on.
Use either when
- You're inspecting an unfamiliar payload interactively. Pick whichever you're more comfortable with. The JSON query tool runs both — try JSONPath first for speed, escalate to jq when selection isn't enough.
Run both in the browser
The free JSON query tool on JSONZen ships JSONPath and a WebAssembly build of jq side by side. Paste your JSON, type the query, see the result instantly — and nothing leaves the browser. Pair it with the JSON tree viewer to navigate unfamiliar payloads before writing the query.
Closing recommendation
Reach for JSONPath first — it covers most ad-hoc selection in one line and the cognitive overhead is tiny. Reach for jq the moment you want to reshape, aggregate, or compute. The wrong tool for the wrong job is what makes JSON querying feel hard; the right tool for the right job is usually trivial.
Related guides
- Flatten Nested JSON: Dot-Notation Keys
How to flatten nested JSON objects and arrays into single-level dot-notation keys. Examples for analytics, CSV export, and config templating with edge cases.