jq — Process JSON on the Command Line

Practical guide to jq — filter, transform and query JSON on the command line with jq's expressive query language, from pretty-print to select().

jq is a lightweight, flexible JSON processor for the command line – you pipe JSON in from curl, cat or any other command and work with it the same way you already use sed, awk or grep for text. Instead of laboriously dissecting JSON with line-oriented tools, you use jq's own query language: filters you chain together with pipes |, field access via dot notation and select() for targeted filtering. With -r you emit raw strings without JSON quotes – perfect when you want to feed values into shell scripts. This guide walks you through the filters and patterns you actually reach for daily, from pretty-print to aggregating whole datasets.

Basic Usage

jq '.' <file> — Pretty-print a JSON file with syntax highlighting.

jq '.' data.json

cat <file> | jq '.' — Pretty-print JSON from stdin (pipe from another command).

curl -s https://api.example.com/users | jq '.'

jq -c '.' <file> — Compact output — print JSON on a single line.

jq -c '.' data.json

jq -r '.' <file> — Raw output — print strings without JSON quotes (useful for shell scripts).

jq -r '.name' user.json

jq -n '<expr>' — Null input mode — evaluate an expression without reading any input.

jq -n '{name: "Alice", age: 30}'

jq -s '.' <files> — Slurp mode — read all inputs into an array instead of processing each line separately.

jq -s '.' a.json b.json

jq -e '<filter>' <file> — Exit with status 1 if the output is false or null. Useful in shell scripts.

jq -e '.active' user.json && echo 'User is active'

Field Access & Paths

jq '.<field>' <file> — Access a top-level field by name.

jq '.name' user.json

jq '.<field>.<nested>' <file> — Access a nested field using dot notation.

jq '.address.city' user.json

jq '.["<field>"]' <file> — Access a field using bracket notation. Required for fields containing special characters or hyphens.

jq '["content-type"]' headers.json

jq '.<field>?' <file> — Optional field access — suppress errors if the field does not exist.

jq '.nickname?' user.json

jq '.a, .b, .c' <file> — Select multiple fields. Outputs each value on a separate line.

jq '.name, .email, .age' user.json

jq 'path(..<field>)' <file> — Return the path (as an array) to a field anywhere in the structure.

jq 'path(..id?)' data.json

Array Operations

jq '.[]' <file> — Iterate over all elements of an array or values of an object.

jq '.[]' users.json

jq '.[<n>]' <file> — Access the element at index n (zero-based). Negative indices count from the end.

jq '.[0]' users.json

jq '.[-1]' <file> — Access the last element of an array.

jq '.[-1]' items.json

jq '.[<from>:<to>]' <file> — Slice an array from index 'from' (inclusive) to 'to' (exclusive).

jq '.[2:5]' items.json

jq 'length' <file> — Return the number of elements in an array, characters in a string, or keys in an object.

jq '.users | length' data.json

jq 'first' <file> — Return the first element produced by an expression.

jq 'first(.users[])' data.json

jq 'last' <file> — Return the last element produced by an expression.

jq 'last(.users[])' data.json

jq 'reverse' <file> — Reverse an array.

jq '.items | reverse' data.json

jq 'flatten' <file> — Flatten a nested array into a single-level array.

jq '.tags | flatten' data.json

jq 'flatten(<depth>)' <file> — Flatten a nested array to the specified depth.

jq '.nested | flatten(1)' data.json

jq 'unique' <file> — Remove duplicate values from an array.

jq '.tags | unique' data.json

jq 'add' <file> — Sum an array of numbers, concatenate strings, or merge an array of objects.

jq '.prices | add' cart.json

Object Construction

jq '{<key>: .<field>}' <file> — Construct a new object with a specific key and value.

jq '{id: .id, username: .name}' user.json

jq '{<field>}' <file> — Shorthand: use field name as both key and value path.

jq '{name, email}' user.json

jq '{(<expr>): <value>}' <file> — Use a computed expression as an object key.

jq '{(.name): .score}' result.json

jq '. + {<key>: <value>}' <file> — Add or overwrite a field in an object using the merge operator.

jq '. + {active: true}' user.json

jq 'del(.<field>)' <file> — Remove a field from an object.

jq 'del(.password)' user.json

jq 'del(.<field>, .<field2>)' <file> — Remove multiple fields from an object.

jq 'del(.password, .token)' user.json

Filtering & Select

jq '.[] | select(.<field> == <value>)' <file> — Filter array elements where a field equals a given value.

jq '.[] | select(.active == true)' users.json

jq '.[] | select(.<field> > <n>)' <file> — Filter elements where a numeric field exceeds a threshold.

jq '.[] | select(.age > 18)' users.json

jq '.[] | select(.<field> | test("<regex>"))' <file> — Filter elements where a string field matches a regular expression.

jq '.[] | select(.email | test("@gmail\.com$"))' users.json

jq '.[] | select(.<field> != null)' <file> — Filter elements where a field is not null (field exists and has a value).

jq '.[] | select(.phone != null)' users.json

jq '.[] | select(has("<field>"))' <file> — Filter elements that contain a specific key.

jq '.[] | select(has("avatar"))' users.json

jq 'if <cond> then <a> else <b> end' <file> — Conditional expression — return one value or another based on a condition.

jq 'if .active then "enabled" else "disabled" end' user.json

jq '.<field> // <default>' <file> — Alternative operator — use a default value if the result is null or false.

jq '.nickname // .name' user.json

Transformation & Map

jq 'map(<expr>)' <file> — Apply an expression to every element of an array. Equivalent to [.[] | ].

jq '.users | map(.name)' data.json

jq 'map(select(<cond>))' <file> — Filter an array to elements matching a condition (map + select).

jq '.users | map(select(.active == true))' data.json

jq 'map_values(<expr>)' <file> — Apply an expression to every value of an object or array.

jq 'map_values(. * 2)' scores.json

jq '[.[] | <expr>]' <file> — Collect results of an expression into a new array using array construction.

jq '[.items[] | .price]' cart.json

jq '.[] | {<key>: .<field>}' <file> — Transform each element of an array into a new object shape.

jq '.users[] | {id: .id, label: .name}' data.json

jq '[.[] | {<key>: .<field>}]' <file> — Transform an array into a new array of reshaped objects.

jq '[.users[] | {id: .id, label: .name}]' data.json

Keys, Values & Entries

jq 'keys' <file> — Return a sorted array of an object's keys.

jq 'keys' config.json

jq 'keys_unsorted' <file> — Return an object's keys in their original insertion order.

jq 'keys_unsorted' config.json

jq 'values' <file> — Return an array of an object's values.

jq '.settings | values' config.json

jq 'has("<key>")' <file> — Return true if the object contains the given key, or the array has the given index.

jq 'has("email")' user.json

jq 'in' <file> — Return true if the left-hand value is a key in the right-hand object.

jq '.[] | in({"a":1, "b":2})' keys.json

jq 'to_entries' <file> — Convert an object to an array of {key, value} pairs.

jq '. | to_entries' config.json

jq 'from_entries' <file> — Convert an array of {key, value} pairs back into an object.

jq '. | from_entries' pairs.json

jq 'with_entries(<expr>)' <file> — Apply an expression to each {key, value} pair of an object. Shorthand for to_entries | map() | from_entries.

jq 'with_entries(select(.value != null))' config.json

Sorting, Grouping & Aggregation

jq 'sort' <file> — Sort an array of comparable values.

jq '.scores | sort' data.json

jq 'sort_by(.<field>)' <file> — Sort an array of objects by a specific field.

jq '.users | sort_by(.name)' data.json

jq 'sort_by(.<field>) | reverse' <file> — Sort an array by a field in descending order.

jq '.users | sort_by(.age) | reverse' data.json

jq 'group_by(.<field>)' <file> — Group an array of objects by the value of a specific field.

jq '.orders | group_by(.status)' data.json

jq 'unique_by(.<field>)' <file> — Remove duplicates from an array based on a specific field.

jq '.users | unique_by(.email)' data.json

jq 'min_by(.<field>)' <file> — Return the element with the minimum value for a given field.

jq '.products | min_by(.price)' data.json

jq 'max_by(.<field>)' <file> — Return the element with the maximum value for a given field.

jq '.products | max_by(.price)' data.json

jq '[.[] | .<field>] | add' <file> — Sum a numeric field across all elements of an array.

jq '[.items[] | .price] | add' cart.json

jq 'reduce .[] as $x (0; . + $x)' <file> — Reduce an array to a single value using an accumulator. Here: sum all numbers.

jq 'reduce .[] as $x (0; . + $x)' numbers.json

String Operations

jq 'test("<regex>")' <file> — Return true if a string matches a regular expression.

jq '.email | test("@gmail\.com$")' user.json

jq 'ascii_downcase' <file> — Convert a string to lowercase.

jq '.name | ascii_downcase' user.json

jq 'ascii_upcase' <file> — Convert a string to uppercase.

jq '.status | ascii_upcase' item.json

jq 'ltrimstr("<prefix>")' <file> — Remove a prefix from a string if present.

jq '.url | ltrimstr("https://")' link.json

jq 'rtrimstr("<suffix>")' <file> — Remove a suffix from a string if present.

jq '.filename | rtrimstr(".json")' file.json

jq 'startswith("<str>")' <file> — Return true if the string starts with the given prefix.

jq '.url | startswith("https")' link.json

jq 'endswith("<str>")' <file> — Return true if the string ends with the given suffix.

jq '.filename | endswith(".json")' file.json

jq 'split("<delim>")' <file> — Split a string into an array on a delimiter.

jq '.tags | split(",")' item.json

jq 'join("<delim>")' <file> — Join an array of strings into a single string with a delimiter.

jq '.tags | join(", ")' item.json

jq '"prefix \(.field) suffix"' <file> — String interpolation — embed expressions inside a string using (...).

jq '"Hello, \(.name)! You are \(.age) years old."' user.json

jq '@base64' <file> — Encode a string as Base64.

jq '.data | @base64' file.json

jq '@base64d' <file> — Decode a Base64-encoded string.

jq '.encoded | @base64d' file.json

jq '@uri' <file> — Percent-encode a string for use in URLs.

jq '.query | @uri' search.json

jq '@csv' <file> — Format an array as a CSV row string.

jq '.rows[] | @csv' data.json

jq '@tsv' <file> — Format an array as a tab-separated values (TSV) row string.

jq '.rows[] | @tsv' data.json

jq '@html' <file> — Escape special HTML characters (<, >, &, ', ") in a string.

jq '.body | @html' post.json

jq '@sh' <file> — Format a string or array as shell-escaped arguments.

jq '@sh "echo \(.name)"' user.json

Types & Conversion

jq 'type' <file> — Return the JSON type of a value: null, boolean, number, string, array, or object.

jq '.value | type' data.json

jq 'tostring' <file> — Convert any value to its JSON string representation.

jq '.count | tostring' data.json

jq 'tonumber' <file> — Convert a string to a number.

jq '.price | tonumber' item.json

jq 'not' <file> — Negate a boolean value.

jq '.active | not' user.json

jq 'infinite' <file> — Produce the IEEE 754 infinity value.

jq -n 'infinite'

jq 'nan' <file> — Produce an IEEE 754 NaN value.

jq -n 'nan'

jq 'isinfinite' <file> — Return true if a number is infinite.

jq '.value | isinfinite' data.json

jq 'isnan' <file> — Return true if a value is NaN.

jq '.value | isnan' data.json

jq 'isnormal' <file> — Return true if a number is a normal finite number.

jq '.value | isnormal' data.json

Recursive & Path Operations

jq '.. | .<field>?' <file> — Recursively search all descendants for a specific field (recursive descent).

jq '.. | .id?' data.json

jq '[paths]' <file> — Return all paths in the JSON structure as arrays.

jq '[paths]' config.json

jq '[leaf_paths]' <file> — Return paths to all leaf (non-container) values.

jq '[leaf_paths]' config.json

jq 'getpath(["<a>","<b>"])' <file> — Get a value at a specific path given as an array.

jq 'getpath(["address","city"])' user.json

jq 'setpath(["<a>","<b>"]; <value>)' <file> — Set a value at a specific path given as an array.

jq 'setpath(["address","city"]; "Berlin")' user.json

jq 'delpaths([["<a>"],["<b>"]])' <file> — Delete values at multiple given paths.

jq 'delpaths([["password"],["token"]])' user.json

Variables & Definitions

jq '.<field> as $<var> | <expr>' <file> — Assign a value to a named variable for reuse in a later expression.

jq '.total as $t | .items[] | {name, pct: (.price / $t * 100)}' data.json

jq --arg <var> '<value>' '<expr>' <file> — Pass a shell variable into jq as a string variable.

jq --arg name "Alice" '.[] | select(.name == $name)' users.json

jq --argjson <var> '<json>' '<expr>' <file> — Pass a shell variable into jq as a parsed JSON value.

jq --argjson minAge 18 '.[] | select(.age >= $minAge)' users.json

jq 'def <name>: <body>; <expr>' <file> — Define a reusable function inline.

jq 'def double: . * 2; .values[] | double' data.json

jq -f <file.jq> <file> — Read a jq filter from a file instead of a command-line argument.

jq -f transform.jq data.json

jq 'env.<VAR>' — Access an environment variable by name.

jq -n 'env.HOME'

jq '$ENV.<VAR>' — Access environment variables via the $ENV object.

jq -n '$ENV.PATH'

Error Handling

jq 'try <expr>' <file> — Attempt an expression and suppress any errors it produces.

jq '.[] | try .value' mixed.json

jq 'try <expr> catch <handler>' <file> — Attempt an expression and run a handler if it fails. The error message is available as the input to the handler.

jq 'try tonumber catch "not a number"' values.json

jq 'error("<message>")' <file> — Raise a custom error and stop processing.

jq 'if .status != "ok" then error("unexpected status") else . end' resp.json

jq '.[]?' <file> — Iterate with the optional operator — suppress errors if the value is not iterable.

jq '.items[]?' data.json

Practical Examples

curl -s <api_url> | jq '.' — Pretty-print a JSON API response.

curl -s https://api.github.com/users/octocat | jq '.'

jq '.[] | select(.status == "active") | .name' <file> — Extract names of all active users as plain strings (-r for raw output).

jq -r '.[] | select(.status == "active") | .name' users.json

jq 'del(.[] | .password, .token)' <file> — Remove sensitive fields from every object in an array.

jq 'del(.[] | .password, .token)' users.json

jq '[.[] | {key: .id, value: .name}] | from_entries' <file> — Convert an array of objects into a lookup map keyed by id.

jq '[.[] | {key: (.id|tostring), value: .name}] | from_entries' users.json

jq 'group_by(.category) | map({category: .[0].category, count: length})' <file> — Count items per category.

jq 'group_by(.category) | map({category: .[0].category, count: length})' items.json

jq -r '[.name, .email, .age | tostring] | @csv' <file> — Export selected fields as a CSV row.

jq -r '.[] | [.name, .email, (.age|tostring)] | @csv' users.json

jq -s '.[0] * .[1]' <file1> <file2> — Deep-merge two JSON objects (the * operator recursively merges objects).

jq -s '.[0] * .[1]' defaults.json overrides.json

jq 'to_entries | map(select(.value == null)) | map(.key)' <file> — Find all keys with null values in an object.

jq 'to_entries | map(select(.value == null)) | map(.key)' config.json

jq -r 'path(..)|map(tostring)|join(".")' <file> — Print all key paths in dot notation (useful for exploring deep structures).

jq -r '[path(..)|map(tostring)|join(".")]|unique[]' config.json

jq -R 'split(" ") | {method: .[0], path: .[1], status: .[2]}' <file> — Parse plain-text lines into JSON objects (-R reads raw strings as input).

jq -R 'split(" ") | {method: .[0], path: .[1]}' access.log

Conclusion

jq is read-only and therefore safe by design – it reads JSON but never alters your source file, writing the result to standard output instead. For everyday work a handful of building blocks gets you far: .field for access, | for chaining, select() for filtering and map() for transformation. Take care with raw output via -r: as soon as you feed the values back into the shell, you are responsible for correct quoting yourself, because spaces, newlines or special characters in the data can otherwise break your script. And treat JSON from untrusted sources with the same scepticism as any other foreign input – validate the structure before you rely on specific fields.

Further Reading

  • jq manual – the official, complete reference for the jq query language
  • jq on Wikipedia – overview of the history and use of jq
  • jq play – interactive playground to try out jq filters right in your browser
  • yq – jq-style processor for YAML and JSON
  • grep – search text files line by line with patterns
  • sed – stream editor for search-and-replace in text