jq

Updated

September 4, 2026

Overview

jq is a command-line JSON processor. It slices, filters, maps, and transforms structured data the way sed/awk do for text lines. Prefer it for APIs, package.json, cloud CLIs, and any tool that emits JSON.

sudo apt install jq

Syntax

jq [options] '<filter>' [file...]
 | jq [options] '<filter>'

Common Options

Option Description
. Identity — pretty-print JSON
-r Raw string output (no JSON quotes)
-c Compact (one value per line)
-s Slurp: all inputs into one array
-n Null input (build JSON from filter only)
-e Exit non-zero if final result is false or null
--arg name value Bind string variable $name
--argjson name json Bind JSON-valued $name
-S Sort object keys
--stream Stream parse huge inputs (advanced)

Key Use Cases

  1. Pretty-print API responses
  2. Extract fields for shell scripts
  3. Filter and map arrays of objects
  4. Build JSON safely from shell variables
  5. CI checks that required keys exist

Examples with Explanations

Pretty-print stdin

curl -sS https://api.github.com/repos/jqlang/jq | jq .

Readable indentation for exploration. -sS shows curl errors without progress meter.

Extract a field

jq -r .name package.json
jq -r '.networkSettings.IPAddress // empty' inspect.json

-r drops quotes so the value is shell-friendly. // empty suppresses nulls.

Map a list of objects to TSV

jq -r '.items[] | [.id, .name, .status] | @tsv' data.json

TSV pipes cleanly into sort, column -t, or spreadsheets.

Filter array elements

jq '.[] | select(.status=="active" and .role=="admin")' users.json
jq '[.[] | select(.cpu > 80)] | length' metrics.json

select keeps matching objects; wrap in [] to recollect into an array.

Nested paths and optional keys

jq -r '.spec.containers[0].image // "missing"' pod.json
jq 'has("error")' response.json

Use explicit paths; has is useful for boolean checks with -e.

Update / reshape objects

jq '.port = 8080 | .debug = false' config.json
jq '{name, version, scripts}' package.json

Filters are expressions: assignment returns the modified object; object construction picks fields.

Flatten and walk arrays

jq -r '.. | objects | select(has("email")) | .email' big.json
jq -r '.[] | .tags[]?' items.json

? avoids errors on missing paths; .. is recursive descent (powerful, easy to overuse).

Build JSON from shell (safe)

jq -n \
  --arg user "$USER" \
  --arg host "$(hostname -f 2>/dev/null || hostname)" \
  --argjson n "$(nproc)" \
  '{user:$user, host:$host, cpus:$n, ts: now|todateiso8601}'

Always prefer --arg / --argjson over interpolating quotes by hand.

Merge two JSON files

jq -s '.[0] * .[1]' base.json overlay.json

-s slurps files into an array; * deep-merges objects (right wins on conflicts).

Exit status for CI

jq -e '.version != null' package.json >/dev/null
jq -e '.[] | select(.severity=="critical") | halt_error(1)' findings.json

-e fails on false/null final output; halt_error aborts mid-stream (jq 1.6+).

Compact logs / NDJSON

jq -c '.[]' array.json              # one object per line
jq -c -r 'select(.level=="error")' app.ndjson

Newline-delimited JSON is ideal for tail -f pipelines.

Understanding Output

jq prints the filter result as JSON by default. Multiple results print one after another. Errors go to stderr. Parse failures are non-zero. With -r, strings lose JSON quoting; numbers/bools still print in a shell-friendly form.

Notes & Pitfalls

  • Filters are programs — learn ., [], |, select, map, keys, has, //.
  • Never build JSON with string concatenation when secrets or user input are involved.
  • Huge single JSON documents may need --stream or preprocessing.
  • YAML is not JSON; use yq (or convert) for YAML.
  • Unicode and locale: raw bytes in invalid UTF-8 can make jq fail.

Additional Resources