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

FilterOutput
.the whole input, unchanged
.name"api"
.meta.count3
."name"same as .name, needed for odd key names
.["name"]same, and the form that takes an expression
.items[0].name"a"
.missingnull, 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
FormMeaning
.a?.a, or nothing if the input cannot be indexed
.[]?iterate, or nothing if the input is not iterable
try fsame as f?
try f catch grun 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

CodeMeaning
0ran fine
1with -e, the last output was false or null
2usage or system error
3the jq program failed to compile
4with -e, the program produced no output at all
5a 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.