The jq Field Guide — 74 copy-paste recipes

Every jq pattern you actually reach for: filtering API responses, reshaping JSON, taming kubectl/aws output, streaming log files, advanced reduce/walk/paths moves. Search below, click COPY, paste in your terminal. No sign-up, no tracking, works offline.

Basics · Select & Filter · Transform · Files, Streams & NDJSON · Advanced Patterns

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:

1. Send exactly 2.44 USDC on BASE to:
0x05FE364d9Ee3Dc0063878C286aF8b3074819Ca5B
2. Order reference: 7a8e6d656f13
3. Watch settlement live: order status page

Exact 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.