Basics
Pretty-print JSON Basics
cat data.json | jq .
The classic. jq re-indents and validates.
Compact output (one line) Basics
jq -c . data.json
Sort keys alphabetically Basics
jq -S . data.json
Read from curl directly Basics
curl -s https://api.github.com/repos/torvalds/linux | jq '.stargazers_count'
Get the first element Basics
jq '.[0]' items.json
Slice an array Basics
jq '.[0:5]' items.json
First five elements, like Python slices.
Last element of array Basics
jq '.[-1]' items.json
Multiple fields at once Basics
jq '{name, email}' user.json
Shorthand object construction — pulls .name and .email.
Nested access safely Basics
jq '.user.profile.bio // "no bio"'
// is the alternative operator — default when null/false.
Check if a key exists Basics
jq 'has("debug")' config.json
Type of a value Basics
jq '.created_at | type'
Raw strings, no quotes Basics
jq -r '.[].name' users.json
-r = raw output; essential in shell pipelines.
Count things Basics
jq '.items | length' feed.json
Select & Filter
Filter by field value Select & Filter
jq '.[] | select(.status == "active")' users.json
Filter with regex match Select & Filter
jq '.[] | select(.email | test("@gmail\\.com$"))' users.json
Case-insensitive contains Select & Filter
jq '.[] | select(.title | ascii_downcase | contains("error"))' logs.json
Numeric comparison Select & Filter
jq '.[] | select(.age >= 18)' people.json
AND / OR conditions Select & Filter
jq '.[] | select(.active and .role == "admin")' users.json
Top 10 by score Select & Filter
jq 'sort_by(-.score) | .[0:10]' players.json
Find max/min item Select & Filter
jq 'max_by(.timestamp)' events.json
min_by works identically.
Unique values only Select & Filter
jq '[.[].category] | unique' products.json
Deduplicate objects entirely Select & Filter
jq 'unique_by(.id)' rows.json
Skip the first N Select & Filter
jq '.[3:]' items.json
Take every 2nd element Select & Filter
jq '.[range(0; length; 2)]' items.json
Group by a field Select & Filter
jq 'group_by(.department)' staff.json
Count per group Select & Filter
jq 'group_by(.status) | map({key: .[0].status, value: length}) | from_entries' tasks.json
Flatten nested arrays Select & Filter
jq '[.[][]]' matrix.json
Or `flatten` for arbitrary depth.
Pick specific keys from each row Select & Filter
jq 'map({id, name})' big.json
Projection before processing = faster + smaller.
Transform
Rename a key Transform
jq 'map(.username = .name) | del(.[].name)' users.json
Delete keys everywhere Transform
jq 'del(.. | select(type == "object").password)' secrets.json
Add a computed field Transform
jq 'map(. + {full_name: "\(.first) \(.last)"})' users.json
String interpolation Transform
jq '"host=\(.hostname) port=\(.port)"' conf.json
Uppercase / lowercase Transform
jq '.[] | .email |= ascii_downcase' users.json
Split a string into array Transform
jq '"a,b,c" | split(",")'
Join array into string Transform
jq '.tags | join(", ")' article.json
Trim whitespace Transform
jq '.name | gsub("^\\s+|\\s+$"; "")' row.json
Replace text (regex) Transform
jq '.body | gsub("https?://[^ ]+"; "[link]")' comment.json
String to number Transform
jq '.port | tonumber' svc.json
And tostring for the reverse.
Arithmetic on fields Transform
jq 'map(.price * .qty) | add' cart.json
Round numbers Transform
jq '.avg | round' stats.json
floor/ceil/fabs also available.
Merge two objects Transform
jq -s '.[0] * .[1]' base.json override.json
* is a deep merge for objects.
Array to lookup table Transform
jq 'map({key: .id, value: .name}) | from_entries' items.json
Invert an object Transform
jq 'to_entries | map({key: .value, value: .key}) | from_entries' map.json
Walk and transform every string Transform
jq 'walk(if type == "string" then gsub("\\r";"") else . end)' dirty.json
Files, Streams & NDJSON
One JSON doc per line (NDJSON) Files, Streams & NDJSON
tail -n 100 app.log | jq -c '{level, msg}'
jq processes each line as its own input.
Convert JSON array to NDJSON Files, Streams & NDJSON
jq -c '.[]' items.json > lines.ndjson
Slurp lines into one array Files, Streams & NDJSON
jq -s '.' events.ndjson
-s reads all inputs into a single array.
Sum values across all lines Files, Streams & NDJSON
jq -s 'map(.amount) | add' txs.ndjson
Load external file into filter Files, Streams & NDJSON
jq --slurpfile cfg config.json '.config = $cfg[0]' main.json
Pass shell vars in safely Files, Streams & NDJSON
jq --arg env "$ENV_NAME" '.env = $arg' deploy.json
--arg (string) / --argjson (JSON). Never interpolate with string ops.
Write pretty JSON to a file Files, Streams & NDJSON
jq . raw.json > formatted.json
Edit a file in place Files, Streams & NDJSON
jq -i 'del(.cache)' settings.json
Requires jq 1.7+.
YAML → JSON → query Files, Streams & NDJSON
yq -o=json config.yaml | jq '.server.port'
Query AWS CLI output Files, Streams & NDJSON
aws ec2 describe-instances | jq '.Reservations[].Instances[].InstanceId'
Query kubectl output Files, Streams & NDJSON
kubectl get pods -o json | jq '.items[] | {name: .metadata.name, phase: .status.phase}'
Parse git log as JSON lines Files, Streams & NDJSON
git log --pretty=format:'%H|%an|%s' | awk -F'|' '{print "{\"sha\":\""$1"\",\"author\":\""$2"\",\"msg\":\""$3"\"}"}' | jq -c .
Advanced Patterns
Recursion: find every key named X Advanced Patterns
jq '[.. | objects | select(has("error"))]' app.json
Paths to all matching values Advanced Patterns
jq 'paths(type == "number")' tree.json
Reduce: running total Advanced Patterns
jq 'reduce .[] as $item (0; . + $item.price)' cart.json
Limit: stop after first match Advanced Patterns
jq 'limit(1; .[] | select(.ok == false))' checks.ndjson
Any / all over a list Advanced Patterns
jq '[.[] .passed] | all' results.json
Conditional logic (if/then/else) Advanced Patterns
jq 'if .score > 90 then "A" elif .score > 80 then "B" else "F" end' grades.json
try/catch bad records Advanced Patterns
jq 'try (.payload | fromjson) catch {bad: true}' stream.ndjson
Generate JSON from nothing Advanced Patterns
jq -n '{now: (now | todate), host: $ENV.HOSTNAME}'
Timestamp math Advanced Patterns
jq 'now - (input.created | fromdateiso8601)' <(echo '{}') new.json
fromdateiso8601/todateiso8601 for RFC3339.
CSV-ish output Advanced Patterns
jq -r '[.id, .name] | @tsv' users.tsv.json
@csv and @tsv handle quoting for you.
URL-encode a value Advanced Patterns
jq -rn --arg q "hello world" '$q | @uri'
Base64 encode/decode Advanced Patterns
jq -rn '"secret" | @base64'
Shell-escape for eval-free loops Advanced Patterns
jq -r '.[] | @sh' args.json
Safe argument passing into xargs/shell.
Compare two JSON files Advanced Patterns
jq -n --slurpfile a old.json --slurpfile b new.json '$b[0] - $a[0]'
Object subtraction shows added/changed keys.
Diff arrays (what's missing) Advanced Patterns
jq -n --slurpfile a a.json --slurpfile b b.json '$a[0] - $b[0]'
Pivot rows to columns Advanced Patterns
jq -r '(.[0] | keys_unsorted) | @tsv, (.[0][] | @tsv)' rows.json
Zip two arrays into objects Advanced Patterns
jq -n '[keys, values] | transpose | map({(.[0]): .[1]}) | add' --args -
Or use `[a] | transpose` on paired arrays.
Self-contained HTTP smoke test Advanced Patterns
curl -s https://httpbin.org/json | jq -e '.slideshow.title' >/dev/null && echo UP || echo DOWN
-e sets exit code by truthiness — CI-friendly.
🔓 Unlock the full 2026 Field Guide sheet — founding rate
The printable single-sheet edition: all 74 recipes plus the ops war-stories appendix, formatted for your terminal wall or team wiki.
Founding rate: the first 20 buyers lock $2 forever — after that it's $5. Slots remaining are counted from verified payments only, never inflated.
Pay directly from this page — takes under 60 seconds:
2.44 USDC on BASE to:0x05FE364d9Ee3Dc0063878C286aF8b3074819Ca5B7a8e6d656f13Exact amount matters — the rail matches your transfer by its unique cent suffix (2.44). USDC on Base settles in seconds. This page is static; your payment is verified on-chain, not by us.