jq (JSON Processor) Cheat Sheet
A reference for jq's filter syntax to query, transform, and reshape JSON data directly from the command line.
Basic Filters
Selecting and extracting fields from JSON.
echo '{"name":"Alice","age":30}' | jq '.' # pretty-printcat data.json | jq '.name' # get field "name"cat data.json | jq '.address.city' # nested fieldcat data.json | jq '.users[0]' # first array itemcat data.json | jq '.users[]' # iterate all itemscat data.json | jq -r '.name' # raw string, no quotes
Filtering & Mapping
Selecting subsets and transforming array elements.
cat data.json | jq '.users[] | select(.age > 18)' # filter itemscat data.json | jq '[.users[].name]' # array of namescat data.json | jq '.users | map(.name)' # same, using mapcat data.json | jq '.users | length' # count itemscat data.json | jq '.users | sort_by(.age)' # sort by fieldcat data.json | jq '.users[] | {name, age}' # reshape object
Building Output
Constructing new JSON structures and CSV output.
cat data.json | jq '{fullName: .name, isAdult: (.age >= 18)}'cat data.json | jq '.users | map({id, label: .name})'cat data.json | jq -r '.users[] | [.name, .age] | @csv'cat data.json | jq '.a // "default"' # fallback if a is null/missingcat data.json | jq 'del(.password)' # remove a key
Key Operators & Functions
Common jq building blocks.
- .- Identity filter; represents the current input
- .[]- Iterates over array elements or object values
- select(cond)- Keeps only values where the condition is true
- map(f)- Applies filter f to each element and collects results into an array
- |- Pipes output of one filter into the next
- ?- Suppresses errors, e.g. `.foo?` skips items missing that key
- @csv / @tsv- Formats an array as a CSV or TSV row
reduce, foreach & Aggregation
Accumulate values across a stream or array, beyond simple map/select.
# Sum a field across all itemscat data.json | jq '[.users[].age] | add'# reduce: build a running total into an objectcat data.json | jq 'reduce .users[] as $u ({}; .[$u.dept] += $u.salary)'# Group-and-count using group_bycat data.json | jq '.users | group_by(.dept) | map({dept: .[0].dept, count: length})'# foreach: emit intermediate accumulator state at each stepcat data.json | jq -c '[foreach .users[] as $u (0; . + $u.age; .)]'# min_by / max_bycat data.json | jq '.users | max_by(.age)'
Recursive Descent & Path Queries
Search arbitrarily nested structures without knowing the exact shape in advance.
# Find every value for a key anywhere in a deeply nested doccat data.json | jq '[.. | .id? // empty]'# Get the paths (as arrays) to every "error" key in the treecat data.json | jq '[paths(type == "object") as $p | select(getpath($p) | has("error")) | $p]'# Flatten nested arrays one levelcat data.json | jq '.groups | flatten(1)'# walk(): transform every value in a tree (e.g. trim all strings)cat data.json | jq 'walk(if type == "string" then ltrimstr(" ") | rtrimstr(" ") else . end)'
Custom Functions, --arg & --slurpfile
Reusable jq functions and passing external data or shell variables into a filter.
# Define a reusable function inlinejq 'def is_adult: .age >= 18; .users[] | select(is_adult)' data.json# Pass a shell variable in safely (avoids string interpolation bugs)threshold=21jq --argjson min "$threshold" '.users[] | select(.age >= $min)' data.json# --arg for string valuesjq --arg dept "Engineering" '.users[] | select(.dept == $dept)' data.json# --slurpfile loads a whole second file as a variablejq --slurpfile rates rates.json \ '.orders[] | .total * $rates[0][.currency]' orders.json# -n --slurp: read entire input array as one array, for cross-record mathjq -s 'add / length' scores.json # average across an array of numbers
Streaming Large JSON with --stream
Process multi-gigabyte JSON files without loading the whole document into memory.
# --stream emits [path, value] pairs incrementally instead of building the whole treejq --stream -c 'select(length==2) | .' huge.json | head# Reconstruct only the objects matching a condition, streaming-stylejq -n --stream 'fromstream(1|truncate_stream(inputs))' huge.json# jq 1.7+: use --seq for newline-delimited JSON streams from an APIcurl -s https://api.example.com/events/stream | jq --seq '.eventType'# Combine with split for parallel-friendly processingjq -c '.[]' huge.json | split -l 100000 - chunk_
Advanced Operators & Idioms
Less common but powerful jq syntax for real-world data wrangling.
- |=- Update-assign: modifies a value in place, e.g. `.users[].active |= not`
- as $x- Binds a value to a named variable for reuse across a longer expression
- input / inputs- Reads the next JSON value(s) from the input stream, useful for cross-referencing two files
- limit(n; expr)- Stops emitting after n results, avoiding a full traversal for large inputs
- try/catch and ?//- `try expr catch handler` for explicit error handling; `?//` for alternative fallback patterns
- ascii_downcase / test / capture- Built-in regex support: `test("^ID-")`, `capture("(?<id>[0-9]+)")` for named-group extraction
- to_entries / from_entries- Converts an object to an array of {key,value} pairs and back, enabling key transforms
- getpath / setpath / delpaths- Programmatic access/mutation of nested values via a path array, e.g. `setpath(["a","b"]; 5)`
Use `jq -c` (compact output) when piping results into another line-oriented tool, and `jq -e` in scripts so jq exits with a non-zero status when the filter produces null or false — handy for shell error checking.