Query and extract data from JSON with a simple, powerful path syntax. A focused, zero-dependency CLI — jq's little sibling for the 90% case.
jq is brilliant but its filter language is its own dialect with a steep learning curve. For the vast majority of real work — "give me the name field of every user over 30" — you shouldn't need to reach for a manual. jpath uses an intuitive dot/bracket path you already know from JavaScript, adds a tiny filter syntax, and stays zero-dependency so it installs instantly and audits clean.
npm install -g jpath-cliOr run it directly with npx jpath ... — no install needed.
# Extract a single value
echo '{"user":{"name":"Ada","age":36}}' | jpath .user.name
# "Ada"
# All names from an array
cat users.json | jpath 'users[*].name'
# Filter + extract
cat users.json | jpath 'users[?(@.age >= 18)].name'
# Every "id" at any depth
cat data.json | jpath '..id'
# Pretty table
cat items.json | jpath '[*]' -o table -k id,name,price| Syntax | Meaning | Example |
|---|---|---|
.foo |
object key foo |
.user.name |
['foo.bar'] |
bracket key (supports dots/spaces) | ['weird.key'] |
[0] |
array index | arr[0] |
[-1] |
last element | arr[-1] |
[*] |
wildcard — all elements / all values | users[*] |
[1:4] |
slice (start inclusive, end exclusive) | arr[1:4] |
..key |
recursive descent — key at any depth |
..id |
[?(expr)] |
filter — keep matching elements | [?(@.price > 10)] |
A leading $ (root) is accepted and ignored: $.user.name ≡ .user.name.
Inside [?(...)], use @ to refer to the current element:
| Expression | Matches when… |
|---|---|
@.active |
active is truthy |
!@.deleted |
deleted is falsy |
@.age > 30 |
numeric comparison (>=, <, <=, ==, !=) |
@.name == 'Ada' |
equality (loose: "10" == 10) |
@.tags contains 'go' |
array/string contains |
@.name startsWith 'A' |
string prefix |
@.name =~ /^A/i |
regex match (/pattern/flags) |
@.id in [1,2,3] |
membership |
Combine with the element path to pull a field: users[?(@.age > 30)].name.
| Format | Description |
|---|---|
json |
Pretty JSON (default) |
compact |
Minified JSON |
jsonl |
Newline-delimited (one JSON per array item) |
raw |
Raw scalar (no quotes) |
table |
Aligned columns (-k id,name to choose) |
keys |
List object keys / array indices |
count |
Length of the result |
-o, --output <fmt> output format
-k, --keys <a,b> columns for table output
-i, --indent <n> JSON indent (default 2)
-r, --raw shortcut for -o raw
--null-as <str> emit this string when the result is null/undefined
-v, --version print version
-h, --help show help
--demo run a built-in demo
# Names of active users, one per line
jpath 'users[?(@.active)].name' data.json -o jsonl
# In-stock products, tabular
jpath 'products[?(@.stock > 0)]' data.json -o table -k sku,name,price
# Count comments on a post
jpath 'post.comments[*]' data.json -o count
# Pull every URL out of a deeply-nested config
jpath '..url' config.json -o jsonl
# Last 3 log entries
jpath 'logs[-3:]' app.json
# Raw scalar for scripting
PRICE=$(jpath '.price' quote.json -r)const { evaluate } = require('jpath');
const data = { users: [{ age: 30 }, { age: 40 }] };
const over30 = evaluate('users[?(@.age > 30)]', data);
// [{ age: 40 }]- Zero dependencies. Pure Node.js, no install-time risk, fast cold start.
- Safe by construction. Filter expressions are parsed by a small hand-written evaluator — no
eval(), ever. Untrusted JSON is safe to query. - Predictable missing values. A missing key or out-of-range index yields
undefinedand a silent exit — ideal for pipelines.
MIT © venture