jq Cheatsheet

Output Flags

Use this jq reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Input flags

These change what jq reads, before any filter runs.

FlagReads
-n, --null-inputnothing, . is null. Use input/inputs to pull explicitly
-R, --raw-inputeach line as a JSON string instead of parsing JSON
-s, --slurpevery input into one array, then run the filter once
-f file, --from-filethe filter itself from a file
--streamthe input as a stream of [path, value] events
--seqinput and output as RFC 7464 json-seq, with 0x1e separators
-L dira module search path for import / include
jq -n '1 + 1'                              # 2, no input read
jq -cn '[inputs]'        multi.json        # [{"a":1},{"a":2}]
jq -c -s '.'             multi.json        # [{"a":1},{"a":2}], same result
jq -c -s 'map(.a) | add' multi.json        # 3
printf 'a\nb\n' | jq -R '.'                # "a" then "b"
printf 'a\nb\n' | jq -Rn -c '[inputs]'     # ["a","b"]
printf 'a\nb\n' | jq -Rs -c 'split("\n")'  # ["a","b",""], -s keeps the last newline
jq -f prog.jq data.json
jq -c --stream '.' <<< '{"a":[1,2]}'
# [["a",0],1] [["a",1],2] [["a",1]] [["a"]]

- Without -n, a leading input consumes the second value, because the first is already .. - -s loads everything into memory. For a huge NDJSON file, iterate the default one-value-at-a-time stream and let jq stay constant-memory. - --seq applies to input as well as output, so piping ordinary JSON into a --seq invocation is a parse error, not a formatting choice.

Output shape

FlagEffect
-c, --compact-outputone line per value, no indentation
--tabindent with tabs
--indent nindent with n spaces, 0 for newline-separated with no indent, max 7
-S, --sort-keyssort object keys on output, recursively
-a, --ascii-outputescape every non-ASCII character as \uXXXX
-C / -Mforce color on / off
--unbufferedflush after each value, for a live pipe
jq -c  '.meta'      data.json    # {"count":3}
jq --tab '.meta'    data.json    # tab-indented
jq --indent 0 '.meta' data.json  # newline-separated, zero indent
jq -cS '.'          data.json    # keys sorted, one line, good for diffing
echo '{"s":"café"}' | jq -a '.s' # "café"
tail -f app.log | jq --unbuffered -c 'select(.level == "error")'

jq -cS on both sides is the standard way to diff two JSON documents, because it removes formatting and key-order noise:

diff <(jq -cS . a.json) <(jq -cS . b.json)
diff <(jq -S . a.json) <(jq -S . b.json)     # pretty, easier to read the hunks

String output: -r, -j, --raw-output0

By default a string output is a JSON string, with quotes and escapes. That is almost never what you want when feeding another shell command.

FlagStrings come out
nonequoted and escaped, "api"
-r, --raw-outputbare, one per line, api
-j, --join-outputbare, no trailing newline, implies -r
--raw-output0bare, NUL-terminated, implies -r
jq    '.name' data.json    # "api"
jq -r '.name' data.json    # api
jq -j '.tags[]' data.json  # webprod, no separator at all
jq --raw-output0 '.tags[]' data.json | xargs -0 -n1 echo

-r only affects values that are strings. A number or an object prints the same either way, so -r is safe to leave on.

--raw-output0 plus xargs -0 is the only safe way to hand jq output to another command when a value could contain a space, a newline, or a quote:

# safe
jq --raw-output0 '.items[].name' data.json | xargs -0 -n1 printf '%s\n'

# unsafe, breaks on any name containing whitespace
jq -r '.items[].name' data.json | xargs -n1 printf '%s\n'

Exit status and -e

CodeMeaning
0ran fine
1with -e, the last output was false or null
2usage or system error, including a file that cannot be read
3the jq program failed to compile
4with -e, the program produced no output at all
5a runtime error, or an explicit error / halt_error
jq -e '.name'  data.json >/dev/null; echo $?   # 0
jq -e '.nope'  data.json >/dev/null; echo $?   # 1, output was null
jq -e 'false'  data.json >/dev/null; echo $?   # 1
jq -e 'empty'  data.json >/dev/null; echo $?   # 4, no output
jq    'false'  data.json >/dev/null; echo $?   # 0, WITHOUT -e
jq    '.a[0]'  <<< '{"a":1}' >/dev/null 2>&1;  echo $?   # 5, runtime error
jq    '.[' data.json >/dev/null 2>&1; echo $?  # 3, compile error

Without -e, a filter that outputs false still exits 0. That is the single most common bug when jq is used as a shell test.

# right
if jq -e '.items | length > 0' data.json >/dev/null; then echo "has items"; fi

# wrong, always true
if jq '.items | length > 0' data.json >/dev/null; then echo "has items"; fi

# distinguish "false" from "no output"
jq -e '.items[] | select(.price > 99)' data.json >/dev/null
case $? in 0) echo found;; 4) echo none;; *) echo error;; esac

halt_error(n) sets an arbitrary code, which is how a jq program signals a specific failure to a script:

jq -rn '"missing required field\n" | halt_error(3)'; echo $?   # 3
jq -e 'if .name then true else "no name\n" | halt_error(2) end' data.json

Flags worth setting by habit

# reading a document you do not know
jq --tab -S '.' data.json | head -40

# a value into a shell variable
name=$(jq -r '.name' data.json)

# an array into a bash array, whitespace safe
mapfile -t -d '' names < <(jq --raw-output0 '.items[].name' data.json)

# NDJSON in, NDJSON out, constant memory
jq -c 'select(.level == "error") | {t: .ts, m: .msg}' app.ndjson

# a shell test
jq -e '.items | all(.price > 0)' data.json >/dev/null || echo "bad prices"

# a stable snapshot for a diff or a checksum
jq -S . config.json | shasum -a 256
CombinationFor
-rany string you will pass to another command
-cNDJSON, while read loops, one line per record
-cSdiffing two documents
-eusing jq as a condition
-n + --argjsonbuilding JSON from shell values with no input document
-Rn 'inputs'reading plain text line by line
--raw-output0 + xargs -0filenames and anything that may contain whitespace
# build a JSON body from shell values, no input file
jq -n --arg name "$NAME" --argjson n 3 '{name: $name, count: $n}'