Overview
jq is the standard tool for slicing, filtering, and transforming JSON on the command line. This card covers the expressions you reach for every day. For querying JSON inside Postgres, see postgres-jsonb. For using jq with API responses, see curl-flags.
All examples use this input unless stated otherwise:
[
{"name": "alice", "age": 30, "tags": ["admin", "user"]},
{"name": "bob", "age": 25, "tags": ["user"]},
{"name": "carol", "age": 35, "tags": ["admin"]}
]Selectors
Access fields and array elements.
| Expression | Result |
|---|---|
. | Identity; pass input through unchanged. |
.name | Field name from an object. |
.["user-name"] | Field with special characters in name. |
.[0] | First element of an array. |
.[-1] | Last element. |
.[2:5] | Slice from index 2 to 4. |
.[] | Iterate array or object values. |
.foo.bar | Chained field access. |
.foo?.bar | Optional: suppress errors if .foo is null or missing. |
keys | Array of object keys. |
values | Array of object values. |
length | Length of array, string, or object. |
has("name") | True if key exists. |
in({"a":1}) | True if the input is a key in the object. |
Use ? to suppress null errors when a field might not exist.
Filters and transforms
Shape and transform data.
| Expression | Result |
|---|---|
.[].name | "alice", "bob", "carol" (one per line). |
[.[].name] | ["alice","bob","carol"] (collect into array). |
{n: .name, a: .age} | Build a new object. |
[.[] | {n: .name}] | Map to new objects. |
select(.age > 28) | Keep only matching elements. |
[.[] | select(.age > 28)] | Filter array. |
sort_by(.age) | Sort array by field. |
sort_by(.age) | reverse | Sort descending. |
group_by(.age) | Group into arrays by field value. |
unique_by(.name) | Deduplicate by field. |
min_by(.age) / max_by(.age) | Min or max element. |
add | Sum numbers, concatenate strings/arrays, merge objects. |
flatten | Recursively flatten nested arrays. |
to_entries | Convert object to [{key, value}] pairs. |
from_entries | Convert [{key, value}] pairs back to object. |
with_entries(.value += 1) | Map over object entries. |
Piping and composition
Chain expressions with |; assign intermediate values with as.
| Expression | Result |
|---|---|
.[] | .name | Stream names. |
.[] | select(.age > 28) | .name | Filtered names. |
[.[] | .age] | add / length | Average age. |
. as $input | ... | Bind input to variable for reuse. |
(.a, .b) | Multiple outputs from one expression. |
if .age > 30 then "senior" else "junior" end | Conditional. |
try .foo catch "missing" | Handle errors gracefully. |
@base64 | Base64-encode a string. |
@json | Serialize to JSON string. |
@csv | Format an array as CSV. |
@tsv | Format an array as TSV. |
@uri | URL-encode a string. |
@html | HTML-escape a string. |
map and select patterns
map applies an expression to every element; select filters elements.
| Pattern | Result |
|---|---|
map(.age | . * 2) | Double every age. |
map(select(.age > 28)) | Filter array inline (equivalent to [.[] | select(...)]). |
map(.tags[]) | Flatten nested arrays one level. |
[.[] | .tags[]] | All tags across all users. |
[.[] | .tags[] | select(. == "admin")] | All occurrences of "admin". |
map(select(.tags | contains(["admin"]))) | Users with “admin” tag. |
map(.name) | sort | unique | Sorted unique names. |
reduce .[] as $u (0; . + $u.age) | Sum ages with reduce. |
Common one-liners
Ready-to-paste expressions for frequent tasks.
| Task | jq expression |
|---|---|
| Pretty-print | jq '.' |
| Compact output | jq -c '.' |
| Raw string output | jq -r '.name' |
| Count items | jq 'length' |
| First match | jq 'first(.[] | select(.age > 28))' |
| Pluck fields | jq '[.[] | {name, age}]' |
| Merge two objects | jq -n '$a * $b' --argjson a '{"x":1}' --argjson b '{"y":2}' |
| Pass shell var | jq --arg name "$NAME" '.[] | select(.name == $name)' |
| Null fallback | jq '.foo // "default"' |
| Recursive descent | jq '.. | .id? | values' |
Use jq -r when the output feeds a shell variable; without -r the value is quoted JSON.
Common gotchas
.fooreturnsnullfor a missing key, not an error. Usehas("foo")orif .foo thento distinguish missing from null.//is the alternative operator:.foo // "default"returns"default"only when.fooisfalseornull. It does not protect against missing keys returningnull..[].foostreams values; wrap in[...]to collect them into an array. Forgetting the brackets means the output is multiple JSON values, not a JSON array.jq -ron an array output still prints the array brackets. Usejq -r '.[]'to get raw lines.- The pipe inside a
map(...)applies to each element; a pipe outsidemapapplies to the whole array.map(. + 1)adds 1 to each;map(.) | addconcatenates or sums the whole array. sort_byrequires comparable types. Mixed-type arrays (numbers and strings) cause an error.