jq Cheatsheet
Basics and Filters
Use this jq reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
The model
jq is a filter language. Every program is a filter that takes one JSON value in and emits zero or more JSON values out. There is no loop keyword and no variable assignment, output count is the control flow.
jq '.' data.json # identity, pretty-print jq -c '.' data.json # compact, one line jq '.name' data.json # one field jq '.items[]' data.json # one output per array element jq 'empty' data.json # zero outputs
Given this file, used throughout:
{"name":"api","version":"2.1.0","tags":["web","prod"],
"items":[{"id":1,"name":"a","price":10,"cat":"x"},
{"id":2,"name":"b","price":20,"cat":"y"},
{"id":3,"name":"c","price":30,"cat":"x"}],
"meta":{"count":3}}Identity and field access
| Filter | Output |
|---|---|
. | the whole input, unchanged |
.name | "api" |
.meta.count | 3 |
."name" | same as .name, needed for odd key names |
.["name"] | same, and the form that takes an expression |
.items[0].name | "a" |
.missing | null, not an error |
A missing key is null, so .a.b.c on {} is null rather than a crash. Indexing the wrong type is an error.
echo '{"a":1}' | jq '.a[0]' # jq: error: Cannot index number with number, exit 5
Quote the key whenever it is not a bare identifier. .["my-key"], ."2fa", .["a b"].
The pipe
| sends every output of the left side into the right side, once each.
jq '.items | .[0] | .name' # "a" jq '.items[] | .name' # "a" "b" "c", three outputs jq '.items[] | select(.price > 15) | .name' # "b" "c"
.a.b is shorthand for .a | .b. Most builtins are written to sit on the right of a pipe, which is why jq programs read left to right like a shell pipeline.
Comma versus pipe
, runs both sides on the same input and concatenates their outputs. | chains. , binds tighter than |.
jq -c '.name, .version' # "api" then "2.1.0" jq -c '.name, .version | length' # 3 then 5, the pipe applies to both jq -c '(.name, .version) | length' # identical, parens for clarity jq -c '.name, (.version | length)' # "api" then 5
Parenthesize whenever a , and a | meet. The default grouping is almost never the one people expect on first read.
The ? operator
? swallows the error from the expression it follows and emits nothing instead.
echo '{"name":"api"}' | jq '.name.x' # error, exit 5 echo '{"name":"api"}' | jq '.name.x?' # no output, exit 0 jq '.items[]?' # nothing if .items is not an array jq '.. | .price? // empty' # every price anywhere, errors skipped
| Form | Meaning |
|---|---|
.a? | .a, or nothing if the input cannot be indexed |
.[]? | iterate, or nothing if the input is not iterable |
try f | same as f? |
try f catch g | run g with the error message as its input |
? hides real bugs as easily as it handles ragged data, so reach for it only where you know the input is mixed.
Zero, one, or many outputs
# 0 outputs jq 'empty' # 1 output jq '[.items[].price] | add' # 60 # 3 outputs, one per element jq '.items[].price' # 10 20 30
Wrapping a multi-output filter in [...] collects the stream into one array, which is how you get back to a single value. Going the other way, .[] explodes an array into a stream. Almost every jq program is one of those two moves.
jq -c '[.items[].id]' # [1,2,3], one output jq -c '.items[].id' # 1 2 3, three outputs
Exit status
| Code | Meaning |
|---|---|
| 0 | ran fine |
| 1 | with -e, the last output was false or null |
| 2 | usage or system error |
| 3 | the jq program failed to compile |
| 4 | with -e, the program produced no output at all |
| 5 | a runtime error, such as indexing the wrong type |
# use jq as a test in a shell script if jq -e '.items | length > 0' data.json > /dev/null; then echo "has items" fi
Without -e, a program that outputs false still exits 0. That is the single most common surprise when jq is used in an if.