jq#
jq is the standard CLI and language for querying and transforming JSON. It’s also a real programming language – filters compose, you can define functions, and the data model has rich operations.
The 90% You’ll Use#
A starter library of jq filters that covers most everyday work; selecting fields, iterating arrays, filtering by predicate, mapping, sorting, grouping, and counting. Each is short enough to type from memory and powerful enough to replace a one-off Python script.
$ jq '.'
$ jq '.name'
$ jq '.users[0]'
$ jq '.users[]'
$ jq '.users[] | .name'
$ jq '.users[] | select(.active)'
$ jq '.users | length'
$ jq '.users | map(.email)'
$ jq '.users | sort_by(.age)'
$ jq '.users | group_by(.team)'
$ jq -r '.name'
Filter Pipelines#
Filters compose left-to-right with |:
$ curl -fsS https://api.example.com/users \
| jq '.[] | select(.role == "admin") | {id, name, email}'
Object Construction#
$ jq '{name: .name, count: (.items | length)}'
$ jq '.users | map({id, name: (.first + " " + .last)})'
A bare identifier in object syntax is shorthand for {name: .name}.
Array Construction#
$ jq '[.users[].email]'
$ jq '[.x, .y, .z]'
Square brackets collect a stream of values into an array.
Updating#
jq is not just a query language; the assignment operators
let one filter rewrite a JSON document in place. Setting a
field, mutating with a function via |=, deleting keys,
and merging objects with + cover the everyday update
forms operators reach for.
$ jq '.user.name = "operator"'
$ jq '.user.age |= . + 1'
$ jq 'del(.password)'
$ jq '. + {ts: now}'
$ jq '.users |= map(. + {active: true})'
Recursion and Walking#
$ jq '..'
$ jq 'paths'
$ jq 'walk(if type == "string" then ascii_downcase else . end)'
Reduce and Foreach#
$ jq '[.orders[].amount] | add'
$ jq 'reduce .orders[] as $o (0; . + $o.amount)'
$ jq 'group_by(.tenant) | map({tenant: .[0].tenant, total: ([.[].amount] | add)})'
Variables and Functions#
$ jq '[.users[] | . as $u | $u.email]'
$ jq 'def slug: ascii_downcase | gsub(" "; "-"); .name | slug'
Streaming#
For files larger than memory.
$ jq --stream '. | select(length == 2 and .[0][0] == "users")' big.json
Stream mode emits paths and values incrementally so jq doesn’t load the whole document.
Common One-Liners#
A short library of jq invocations worth keeping near the shell. CSV projection, pretty-printing versus compact output, NDJSON enrichment, two-file diffs, and shell-variable parameterization; each is the kind of pattern that makes jq feel like a Swiss-army tool.
$ jq -r '.[] | [.id, .name] | @csv'
$ jq '.'
$ jq -c '.'
$ jq -c '. + {ts: now}' input.ndjson > output.ndjson
$ jq -n --argfile a a.json --argfile b b.json '$a - $b'
$ jq --arg name "$NAME" '.name = $name'
Alternatives#
The other CLIs an operator may meet alongside or instead of
jq. gojq and jaq are reimplementations with different
performance trade-offs; JMESPath is a separate query language
in cloud SDKs; gron, dasel, and yq round out the
ecosystem with adjacent and complementary capabilities.
gojq, pure-Go reimplementation; drop-in for most uses.
jaq, Rust reimplementation; faster on most workloads.
JMESPath, a different JSON query language used by AWS CLI
--query, Azure CLI, and many SDKs:users[?role=='admin'].{name: name, email: email}gron, flatten JSON to greppable
.paths; complements jq for ad-hoc exploration.dasel, multi-format query (JSON / YAML / TOML / XML).
yq, jq for YAML.
JSONPath#
Another JSON query DSL, originally inspired by XPath.
$.store.book[*].author # all authors
$..author # any author at any depth
$..book[?(@.price < 10)] # filter
$..book[0,1] # first two
Used by Kubernetes (kubectl -o jsonpath=...), some monitoring tools,
and Postman tests. Less expressive than jq; more standardized in
RFC 9535 (2024).
When to Reach for jq#
The kinds of work where jq is the right tool. Ad-hoc exploration, shell-script glue, JSON-to-CSV projection, and quick reshaping between API contracts are all sweet spots. Application code wants the runtime’s own JSON library; truly large datasets want a real query engine.
Ad-hoc JSON exploration on the command line.
Shell scripts that consume JSON APIs.
Quick transformations between JSON structures.
CSV / NDJSON ↔ JSON conversions.
When not to.
Application code, use the language’s JSON parser plus normal code.
Very large datasets where streaming alternatives (Spark, ClickHouse, DuckDB) make more sense.