DevToolBoxFREE
Blog

jq Command Tutorial & Examples

12 min readby DevToolBox

jq is a lightweight, flexible command-line JSON processor that has become an indispensable tool for every developer working with APIs, configuration files, or log data. This comprehensive tutorial covers jq command examples from basic filters to advanced data transformations, so you can master JSON processing in your terminal.

Format and view JSON with our online JSON Formatter →

1. What is jq?

jq is like sed for JSON data — a command-line tool that lets you slice, filter, map, and transform structured data with ease. It is written in C with zero runtime dependencies, making it fast and portable across all major platforms.

jq takes JSON input (from a file or stdin), applies one or more filters, and produces JSON output. Its expression language is powerful yet concise, allowing complex data transformations in a single command.

Installation

Install jq on any platform in seconds:

# Ubuntu / Debian
sudo apt-get install jq

# macOS (Homebrew)
brew install jq

# Windows (Chocolatey)
choco install jq

# Windows (Scoop)
scoop install jq

# Alpine Linux
apk add jq

# From source / binary
# Download from https://jqlang.github.io/jq/download/
wget https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64
chmod +x jq-linux-amd64 && sudo mv jq-linux-amd64 /usr/local/bin/jq

# Verify installation
jq --version

Basic Syntax

The simplest jq command is the identity filter . which pretty-prints JSON input:

# Pretty-print JSON (identity filter)
echo '{"name":"Alice","age":30,"skills":["go","rust"]}' | jq '.'

# Output:
# {
#   "name": "Alice",
#   "age": 30,
#   "skills": [
#     "go",
#     "rust"
#   ]
# }

# Read from a file
jq '.' data.json

# Compact output (single line)
jq -c '.' data.json

# Raw string output (no quotes)
echo '{"name":"Alice"}' | jq -r '.name'
# Output: Alice  (without quotes)

# Sort keys alphabetically
echo '{"z":1,"a":2,"m":3}' | jq -S '.'

2. Basic Filters

jq filters extract and transform data from JSON input. The dot notation is the foundation of everything in jq.

Object Field Access

# Sample JSON
# {"name": "Alice", "age": 30, "address": {"city": "NYC", "zip": "10001"}}

# Access a top-level field
echo '{"name":"Alice","age":30}' | jq '.name'
# "Alice"

# Access a nested field
echo '{"address":{"city":"NYC","zip":"10001"}}' | jq '.address.city'
# "NYC"

# Multiple fields (comma-separated)
echo '{"name":"Alice","age":30,"role":"admin"}' | jq '.name, .age'
# "Alice"
# 30

# Optional field access (no error if missing)
echo '{"name":"Alice"}' | jq '.email?'
# null

# Field with special characters (use quotes)
echo '{"my-field": 42}' | jq '.["my-field"]'
# 42

Array Access

# Access by index
echo '[10,20,30,40,50]' | jq '.[0]'
# 10

# Negative index (from end)
echo '[10,20,30,40,50]' | jq '.[-1]'
# 50

# Array slice
echo '[10,20,30,40,50]' | jq '.[1:3]'
# [20, 30]

# Slice from start
echo '[10,20,30,40,50]' | jq '.[:2]'
# [10, 20]

# Slice to end
echo '[10,20,30,40,50]' | jq '.[3:]'
# [40, 50]

# Iterate all elements (array value iterator)
echo '[1,2,3]' | jq '.[]'
# 1
# 2
# 3

# Iterate object values
echo '{"a":1,"b":2,"c":3}' | jq '.[]'
# 1
# 2
# 3

Constructing New Objects & Arrays

# Build a new object from fields
echo '{"first":"Alice","last":"Smith","age":30}' | jq '{name: .first, years: .age}'
# {"name": "Alice", "years": 30}

# Wrap results in an array
echo '{"a":1,"b":2,"c":3}' | jq '[.a, .b, .c]'
# [1, 2, 3]

# Collect iterator results into an array
echo '[1,2,3,4,5]' | jq '[.[] | . * 2]'
# [2, 4, 6, 8, 10]

3. Pipe & Chaining

Just like Unix shell pipes, jq uses | to chain filters together. The output of the left filter becomes the input of the right filter. This composability is what makes jq so powerful.

# Chain filters with pipe
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' | \
  jq '.users[] | .name'
# "Alice"
# "Bob"

# Multiple pipes
echo '{"data":{"items":[{"id":1,"val":"a"},{"id":2,"val":"b"}]}}' | \
  jq '.data.items[] | .val'
# "a"
# "b"

# Pipe into object construction
echo '{"users":[{"first":"Alice","last":"Smith"},{"first":"Bob","last":"Jones"}]}' | \
  jq '.users[] | {full_name: (.first + " " + .last)}'
# {"full_name": "Alice Smith"}
# {"full_name": "Bob Jones"}

# Pipe with length
echo '{"users":[{"name":"Alice"},{"name":"Bob"},{"name":"Charlie"}]}' | \
  jq '.users | length'
# 3

# Pipe with multiple outputs
echo '{"a":{"x":1},"b":{"x":2}}' | jq '.a, .b | .x'
# 1
# 2

# Parentheses for grouping
echo '{"a":1,"b":2}' | jq '(.a + .b) * 2'
# 6

4. Select & Filter

The select() function filters elements based on a condition. Combined with map(), it becomes a powerful query engine for JSON data.

# select() - filter by condition
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25},{"name":"Charlie","age":35}]' | \
  jq '.[] | select(.age > 28)'
# {"name": "Alice", "age": 30}
# {"name": "Charlie", "age": 35}

# map(select()) - filter and keep as array
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25},{"name":"Charlie","age":35}]' | \
  jq 'map(select(.age >= 30))'
# [{"name": "Alice", "age": 30}, {"name": "Charlie", "age": 35}]

# String matching with select
echo '[{"name":"Alice"},{"name":"Bob"},{"name":"Anna"}]' | \
  jq '.[] | select(.name | startswith("A"))'
# {"name": "Alice"}
# {"name": "Anna"}

# select with contains
echo '[{"tags":["go","api"]},{"tags":["python","ml"]},{"tags":["go","cli"]}]' | \
  jq '.[] | select(.tags | contains(["go"]))'
# {"tags": ["go", "api"]}
# {"tags": ["go", "cli"]}

# select with test (regex)
echo '[{"email":"alice@gmail.com"},{"email":"bob@company.org"},{"email":"charlie@gmail.com"}]' | \
  jq '.[] | select(.email | test("gmail"))'
# {"email": "alice@gmail.com"}
# {"email": "charlie@gmail.com"}

# has() - check if key exists
echo '{"name":"Alice","email":"alice@example.com"}' | jq 'has("email")'
# true

echo '[{"name":"Alice","email":"a@b.com"},{"name":"Bob"}]' | \
  jq '.[] | select(has("email"))'
# {"name": "Alice", "email": "a@b.com"}

# in() - check if key exists in object
echo '{"admin":true,"user":true}' | jq '"admin" | in({"admin":true,"user":true})'
# true

# type checks
echo '[1,"hello",null,true,[],{}]' | jq '.[] | select(type == "string")'
# "hello"

# Negated select (NOT matching)
echo '[{"status":"active"},{"status":"inactive"},{"status":"active"}]' | \
  jq '.[] | select(.status != "active")'
# {"status": "inactive"}

5. String Interpolation & Formatting

jq provides string interpolation with \(expr) inside double quotes, plus several format strings for converting data to different output formats.

# String interpolation with \()
echo '{"name":"Alice","age":30}' | jq '"\(.name) is \(.age) years old"'
# "Alice is 30 years old"

# Use -r for raw output (no surrounding quotes)
echo '{"name":"Alice","age":30}' | jq -r '"\(.name) is \(.age) years old"'
# Alice is 30 years old

# @text - plain text (default)
echo '"hello"' | jq '@text'
# "hello"

# @html - HTML-escaped
echo '"<script>alert(1)</script>"' | jq '@html'
# "&lt;script&gt;alert(1)&lt;/script&gt;"

# @csv - CSV format (use with -r)
echo '["Alice",30,"NYC"]' | jq -r '@csv'
# "Alice",30,"NYC"

# @tsv - Tab-separated values
echo '["Alice",30,"NYC"]' | jq -r '@tsv'
# Alice	30	NYC

# @json - JSON-encode a string
echo '"hello world"' | jq '@json'
# ""hello world""

# @base64 - Base64 encode
echo '"hello world"' | jq '@base64'
# "aGVsbG8gd29ybGQ="

# @base64d - Base64 decode
echo '"aGVsbG8gd29ybGQ="' | jq '@base64d'
# "hello world"

# @uri - URI-encode
echo '"hello world&foo=bar"' | jq '@uri'
# "hello%20world%26foo%3Dbar"

# Combining formats: CSV from array of arrays
echo '[[1,"Alice",30],[2,"Bob",25]]' | jq -r '.[] | @csv'
# 1,"Alice",30
# 2,"Bob",25

# Build formatted table with string interpolation
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' | \
  jq -r '.[] | "\(.name)\t\(.age)"'
# Alice	30
# Bob	25

6. Array Operations

jq provides a rich set of built-in functions for working with arrays: sorting, grouping, filtering, flattening, and more.

# length
echo '[1,2,3,4,5]' | jq 'length'
# 5

# map() - transform each element
echo '[1,2,3,4,5]' | jq 'map(. * 10)'
# [10, 20, 30, 40, 50]

echo '[{"name":"Alice"},{"name":"Bob"}]' | jq 'map(.name)'
# ["Alice", "Bob"]

# sort and sort_by
echo '[3,1,4,1,5,9,2,6]' | jq 'sort'
# [1, 1, 2, 3, 4, 5, 6, 9]

echo '[{"name":"Charlie","age":35},{"name":"Alice","age":30},{"name":"Bob","age":25}]' | \
  jq 'sort_by(.age)'
# [{"name":"Bob","age":25},{"name":"Alice","age":30},{"name":"Charlie","age":35}]

# Reverse sort
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25},{"name":"Charlie","age":35}]' | \
  jq 'sort_by(.age) | reverse'

# group_by
echo '[{"dept":"eng","name":"Alice"},{"dept":"sales","name":"Bob"},{"dept":"eng","name":"Charlie"}]' | \
  jq 'group_by(.dept)'
# [[{"dept":"eng","name":"Alice"},{"dept":"eng","name":"Charlie"}],[{"dept":"sales","name":"Bob"}]]

# unique and unique_by
echo '[1,2,2,3,3,3]' | jq 'unique'
# [1, 2, 3]

echo '[{"city":"NYC"},{"city":"LA"},{"city":"NYC"}]' | jq 'unique_by(.city)'
# [{"city":"LA"},{"city":"NYC"}]

# flatten
echo '[[1,2],[3,[4,5]],6]' | jq 'flatten'
# [1, 2, 3, 4, 5, 6]

# flatten with depth
echo '[[1,[2]],[3,[4,[5]]]]' | jq 'flatten(1)'
# [1, [2], 3, [4, [5]]]

# first, last, nth
echo '[10,20,30,40,50]' | jq 'first'
# 10
echo '[10,20,30,40,50]' | jq 'last'
# 50

# min, max, min_by, max_by
echo '[3,1,4,1,5,9]' | jq 'min'
# 1
echo '[3,1,4,1,5,9]' | jq 'max'
# 9

echo '[{"name":"Alice","score":85},{"name":"Bob","score":92}]' | jq 'max_by(.score)'
# {"name": "Bob", "score": 92}

# add - sum numbers or concatenate arrays/strings
echo '[1,2,3,4,5]' | jq 'add'
# 15

echo '[["a","b"],["c","d"]]' | jq 'add'
# ["a", "b", "c", "d"]

# indices / index
echo '["a","b","c","b","a"]' | jq 'index("b")'
# 1

# limit and until
echo 'null' | jq '[limit(5; range(100))]'
# [0, 1, 2, 3, 4]

# range - generate number sequences
echo 'null' | jq '[range(5)]'
# [0, 1, 2, 3, 4]

echo 'null' | jq '[range(2;8;2)]'
# [2, 4, 6]

7. Object Operations

jq makes it easy to inspect, transform, and reconstruct JSON objects using built-in functions like keys, values, to_entries, and with_entries.

# keys - get all keys as sorted array
echo '{"name":"Alice","age":30,"city":"NYC"}' | jq 'keys'
# ["age", "city", "name"]

# keys_unsorted - preserve original order
echo '{"name":"Alice","age":30,"city":"NYC"}' | jq 'keys_unsorted'
# ["name", "age", "city"]

# values - get all values
echo '{"name":"Alice","age":30,"city":"NYC"}' | jq 'values'
# ["Alice", 30, "NYC"]

# to_entries - convert to key-value pair array
echo '{"name":"Alice","age":30}' | jq 'to_entries'
# [{"key": "name", "value": "Alice"}, {"key": "age", "value": 30}]

# from_entries - convert key-value pairs back to object
echo '[{"key":"name","value":"Alice"},{"key":"age","value":30}]' | jq 'from_entries'
# {"name": "Alice", "age": 30}

# from_entries also works with "name"/"value" pairs
echo '[{"name":"x","value":1},{"name":"y","value":2}]' | jq 'from_entries'
# {"x": 1, "y": 2}

# with_entries - transform entries (to_entries | map(f) | from_entries)
echo '{"name":"Alice","age":30}' | jq 'with_entries(.key = "prefix_" + .key)'
# {"prefix_name": "Alice", "prefix_age": 30}

# with_entries - filter by key
echo '{"name":"Alice","age":30,"_internal":true}' | \
  jq 'with_entries(select(.key | startswith("_") | not))'
# {"name": "Alice", "age": 30}

# Add / merge objects with +
echo '{"a":1,"b":2}' | jq '. + {"c":3,"d":4}'
# {"a": 1, "b": 2, "c": 3, "d": 4}

# Merge with override
echo '{"a":1,"b":2}' | jq '. + {"b":99}'
# {"a": 1, "b": 99}

# * for recursive merge
echo '{"a":{"x":1},"b":2}' | jq '. * {"a":{"y":2}}'
# {"a": {"x": 1, "y": 2}, "b": 2}

# del() - remove a key
echo '{"name":"Alice","age":30,"tmp":true}' | jq 'del(.tmp)'
# {"name": "Alice", "age": 30}

# del() multiple keys
echo '{"a":1,"b":2,"c":3,"d":4}' | jq 'del(.b, .d)'
# {"a": 1, "c": 3}

# Update a field with |=
echo '{"name":"alice","age":30}' | jq '.name |= ascii_upcase'
# {"name": "ALICE", "age": 30}

# Update nested field
echo '{"user":{"name":"Alice","score":85}}' | jq '.user.score |= . + 10'
# {"user": {"name": "Alice", "score": 95}}

8. Conditionals & Error Handling

jq supports if-then-else expressions, the alternative operator //, and try-catch for robust data processing pipelines.

# if-then-else
echo '{"age":25}' | jq 'if .age >= 18 then "adult" else "minor" end'
# "adult"

# if-then-elif-else
echo '{"score":85}' | jq '
  if .score >= 90 then "A"
  elif .score >= 80 then "B"
  elif .score >= 70 then "C"
  else "F"
  end'
# "B"

# if-then-else with map
echo '[{"name":"Alice","age":30},{"name":"Bob","age":15}]' | \
  jq 'map(if .age >= 18 then . + {"status":"adult"} else . + {"status":"minor"} end)'
# [{"name":"Alice","age":30,"status":"adult"},{"name":"Bob","age":15,"status":"minor"}]

# Alternative operator // (default value if null or false)
echo '{"name":"Alice"}' | jq '.email // "not set"'
# "not set"

echo '{"name":"Alice","email":"alice@example.com"}' | jq '.email // "not set"'
# "alice@example.com"

# Nested alternative
echo '{"config":{}}' | jq '.config.timeout // .config.default_timeout // 30'
# 30

# try-catch (jq 1.6+)
echo '"not a number"' | jq 'try tonumber catch "invalid number"'
# "invalid number"

# try without catch (silently suppress errors)
echo '{"a":1}' | jq 'try .b.c.d'
# (no output, no error)

# try with array of mixed types
echo '[1,"two",3,"four",5]' | jq '[.[] | try (. + 10)]'
# [11, 13, 15]

# Error handling with if and type
echo '{"value":"hello"}' | jq '
  if (.value | type) == "number" then .value * 2
  else "expected number, got \(.value | type)"
  end'
# "expected number, got string"

# empty - produce no output (useful in select-like patterns)
echo '[1,2,3,4,5]' | jq '.[] | if . > 3 then . else empty end'
# 4
# 5

9. Real-World Examples

Here are practical jq patterns you will use daily when working with APIs, cloud services, and log files.

Parse GitHub API Responses

# List repos - extract name, stars, and language
curl -s "https://api.github.com/users/torvalds/repos?per_page=5" | \
  jq '.[] | {name: .name, stars: .stargazers_count, lang: .language}'

# Find most starred repo
curl -s "https://api.github.com/users/torvalds/repos?per_page=100" | \
  jq 'max_by(.stargazers_count) | {name, stars: .stargazers_count}'

# List open issues with labels
curl -s "https://api.github.com/repos/jqlang/jq/issues?state=open&per_page=5" | \
  jq '.[] | {title: .title, labels: [.labels[].name], created: .created_at}'

# Count repos by language
curl -s "https://api.github.com/users/octocat/repos" | \
  jq 'group_by(.language) | map({lang: .[0].language, count: length}) | sort_by(.count) | reverse'

AWS CLI Output Processing

# List EC2 instances - extract ID, type, state
aws ec2 describe-instances | \
  jq '.Reservations[].Instances[] | {
    id: .InstanceId,
    type: .InstanceType,
    state: .State.Name,
    name: (.Tags // [] | map(select(.Key == "Name")) | first | .Value // "unnamed")
  }'

# Find running instances only
aws ec2 describe-instances | \
  jq '[.Reservations[].Instances[] | select(.State.Name == "running")] | length'

# List S3 buckets with creation dates
aws s3api list-buckets | \
  jq '.Buckets | sort_by(.CreationDate) | .[] | "\(.Name) - \(.CreationDate)"'

# Get Lambda function names and runtimes
aws lambda list-functions | \
  jq '.Functions[] | {name: .FunctionName, runtime: .Runtime, memory: .MemorySize}'

Log Processing

# Parse JSON log lines (one JSON object per line)
cat app.log | jq -r 'select(.level == "error") | "\(.timestamp) \(.message)"'

# Count errors by type
cat app.log | jq -s 'map(select(.level == "error")) | group_by(.error_code) |
  map({code: .[0].error_code, count: length}) | sort_by(.count) | reverse'

# Extract slow requests (>1s)
cat access.log | jq 'select(.response_time_ms > 1000) |
  {path: .request_path, time_ms: .response_time_ms, method: .method}'

# Aggregate stats from JSON logs
cat app.log | jq -s '{
  total: length,
  errors: map(select(.level == "error")) | length,
  avg_response_ms: (map(.response_time_ms) | add / length),
  unique_users: (map(.user_id) | unique | length)
}'

Docker & Kubernetes

# Docker: list containers with ports
docker inspect $(docker ps -q) | \
  jq '.[] | {name: .Name, image: .Config.Image, ports: .NetworkSettings.Ports}'

# Docker: get container IP addresses
docker network inspect bridge | \
  jq '.[0].Containers | to_entries[] | {name: .value.Name, ip: .value.IPv4Address}'

# Kubernetes: get pod names and status
kubectl get pods -o json | \
  jq '.items[] | {name: .metadata.name, status: .status.phase, restarts: (.status.containerStatuses[0].restartCount // 0)}'

# Kubernetes: find pods not in Running state
kubectl get pods -o json | \
  jq '[.items[] | select(.status.phase != "Running") | .metadata.name]'

10. jq with curl

The curl | jq pipeline is one of the most common patterns in API development. Pipe API responses directly into jq for instant formatting and data extraction.

# Basic: pretty-print API response
curl -s https://api.github.com/users/octocat | jq '.'

# Extract specific fields
curl -s https://api.github.com/users/octocat | jq '{name, bio, public_repos}'

# Process paginated API results
for page in 1 2 3; do
  curl -s "https://api.example.com/items?page=$page" | jq '.items[]'
done | jq -s 'length'

# POST then parse response
curl -s -X POST https://api.example.com/auth \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"secret"}' | \
  jq -r '.token'

# Chain: get token, then use it
TOKEN=$(curl -s -X POST https://api.example.com/auth \
  -d '{"user":"admin","pass":"secret"}' | jq -r '.token')
curl -s -H "Authorization: Bearer $TOKEN" https://api.example.com/data | jq '.'

# Save extracted data to file
curl -s https://api.github.com/users/octocat/repos | \
  jq '[.[] | {name, stars: .stargazers_count, url: .html_url}]' > repos.json

# Handle errors in API response
curl -s https://api.example.com/data | \
  jq 'if .error then "Error: \(.error.message)" else .data end'

# Headers + jq for debugging
curl -s -D- https://api.example.com/data | \
  sed '1,/^\r$/d' | jq '.'

# Multiple API calls with xargs
echo "octocat torvalds gvanrossum" | tr ' ' '\n' | \
  xargs -I {} curl -s "https://api.github.com/users/{}" | \
  jq '{login, name, public_repos}'

# GraphQL API with jq
curl -s -X POST https://api.github.com/graphql \
  -H "Authorization: bearer $GITHUB_TOKEN" \
  -d '{"query":"{ viewer { login name }}"}' | \
  jq '.data.viewer'

11. Advanced jq

For complex data transformations, jq offers reduce, foreach, custom function definitions, environment variables, and command-line arguments.

reduce

# Sum with reduce
echo '[1,2,3,4,5]' | jq 'reduce .[] as $x (0; . + $x)'
# 15

# Build object from array with reduce
echo '[["name","Alice"],["age","30"],["city","NYC"]]' | \
  jq 'reduce .[] as $pair ({}; . + {($pair[0]): $pair[1]})'
# {"name": "Alice", "age": "30", "city": "NYC"}

# Running total with reduce
echo '[10,20,30,40]' | \
  jq 'reduce .[] as $x ([]; . + [((. | last) // 0) + $x])'
# [10, 30, 60, 100]

# Count occurrences with reduce
echo '["a","b","a","c","b","a"]' | \
  jq 'reduce .[] as $x ({}; .[$x] = ((.[$x] // 0) + 1))'
# {"a": 3, "b": 2, "c": 1}

foreach

# foreach produces intermediate results
echo 'null' | jq '[foreach range(5) as $x (0; . + $x)]'
# [0, 1, 3, 6, 10]

# foreach with extract expression
echo 'null' | jq '[foreach range(1;6) as $x (1; . * $x; .)]'
# [1, 2, 6, 24, 120]  (factorials)

Custom Functions (def)

# Define a reusable function
echo '["hello","world"]' | jq 'def capitalize: (.[0:1] | ascii_upcase) + .[1:]; map(capitalize)'
# ["Hello", "World"]

# Function with parameters
echo '[1,2,3,4,5]' | jq 'def clamp(min; max): if . < min then min elif . > max then max else . end; map(clamp(2;4))'
# [2, 2, 3, 4, 4]

# Recursive function
echo '{"a":{"b":{"c":{"d":"found"}}}}' | \
  jq 'def depth: if type == "object" then (to_entries | map(.value | depth) | max) + 1 elif type == "array" then (map(depth) | max) + 1 else 0 end; depth'
# 4

# Function for formatting bytes
echo '{"size":1073741824}' | jq 'def bytes:
  if . >= 1073741824 then "\(. / 1073741824 | floor)GB"
  elif . >= 1048576 then "\(. / 1048576 | floor)MB"
  elif . >= 1024 then "\(. / 1024 | floor)KB"
  else "\(.)B"
  end;
.size | bytes'
# "1GB"

Environment Variables & Arguments

# Access environment variables with $ENV
export MY_VAR="hello"
echo 'null' | jq '$ENV.MY_VAR'
# "hello"

# Access all env vars
echo 'null' | jq '$ENV | keys[:5]'

# --arg: pass string arguments
jq -n --arg name "Alice" --arg age "30" '{name: $name, age: ($age | tonumber)}'
# {"name": "Alice", "age": 30}

# --argjson: pass JSON arguments
jq -n --argjson count 5 --argjson active true '{count: $count, active: $active}'
# {"count": 5, "active": true}

# --slurpfile: read JSON from file into variable
echo '{"name":"Alice"}' > /tmp/user.json
jq -n --slurpfile user /tmp/user.json '$user[0]'
# {"name": "Alice"}

# --slurp (-s): read all inputs into an array
echo -e '{"a":1}\n{"a":2}\n{"a":3}' | jq -s 'map(.a) | add'
# 6

# --null-input (-n): don't read stdin
jq -n '{timestamp: now, message: "hello"}'

# --rawfile: read raw file content as string
jq -n --rawfile tmpl template.txt '$tmpl'

# --jsonargs: pass remaining args as JSON
jq -n '$ARGS.positional' --jsonargs 1 2 3
# [1, 2, 3]

# --join-output / -j: no newline at end
echo '{"name":"Alice"}' | jq -j '.name'
# Alice (no trailing newline)

# --exit-status / -e: set exit code based on output
echo '{"ok":true}' | jq -e '.ok' > /dev/null && echo "success"
# success

12. Cheat Sheet: Quick Reference

The most commonly used jq patterns at a glance. Bookmark this table for quick lookup.

PatternDescriptionExample
.Identity (pretty-print)jq '.'
.fieldGet object fieldjq '.name'
.a.b.cNested field accessjq '.user.address.city'
.[n]Array indexjq '.[0]'
.[]Iterate array/object valuesjq '.users[]'
.[m:n]Array slicejq '.[2:5]'
|Pipe (chain filters)jq '.[] | .name'
select()Filter by conditionjq '.[] | select(.age>30)'
map()Transform array elementsjq 'map(.name)'
sort_by()Sort array by fieldjq 'sort_by(.age)'
group_by()Group by fieldjq 'group_by(.type)'
unique_by()Deduplicate by fieldjq 'unique_by(.id)'
keysGet object keysjq 'keys'
valuesGet object valuesjq 'values'
to_entriesObject to key-value pairsjq 'to_entries'
from_entriesKey-value pairs to objectjq 'from_entries'
with_entries()Transform entries in placejq 'with_entries(.key|=ascii_upcase)'
lengthArray/object/string lengthjq '.items | length'
//Alternative (default value)jq '.x // "default"'
del()Delete key from objectjq 'del(.tmp)'
addSum array / concatjq '[.[] | .score] | add'
flattenFlatten nested arraysjq 'flatten'
@csv / @tsvFormat as CSV/TSVjq -r '.[] | @csv'
@base64Base64 encodejq '.token | @base64'
--arg k vPass string argumentjq --arg n "Alice" '.name==$n'
-rRaw output (no quotes)jq -r '.name'
-sSlurp: read all inputs as arrayjq -s 'add'
-cCompact outputjq -c '.'
-eExit status based on outputjq -e '.ok'
reduceAccumulate valuesjq 'reduce .[] as $x (0;.+$x)'

Frequently Asked Questions

What is jq used for?

jq is a command-line JSON processor used for parsing, filtering, transforming, and formatting JSON data. It is commonly used to process API responses, parse log files, transform configuration files, and extract specific fields from complex JSON structures. Think of it as grep/sed/awk but purpose-built for JSON.

How do I pretty-print JSON with jq?

Simply pipe JSON into jq with the identity filter: echo '{"name":"Alice","age":30}' | jq '.' This will output the JSON with proper indentation and syntax highlighting. You can also use jq '.' file.json to pretty-print a JSON file. To use compact output instead, add the -c flag: jq -c '.' file.json.

How do I extract a nested field from JSON using jq?

Use dot notation to navigate nested objects: jq '.user.address.city' data.json. For arrays, use .[index] to access specific elements: jq '.users[0].name' data.json. To iterate over all array elements, use .[]: jq '.users[].name' data.json. You can chain these as deep as needed.

What is the difference between jq map() and select()?

map() applies a transformation to every element in an array and returns a new array of the same length. select() filters elements based on a condition, returning only those that match. They are often combined: jq '.users | map(select(.age > 30))' filters the users array to only include users older than 30. map() transforms, select() filters.

How do I use jq with curl to parse API responses?

Pipe the curl output directly into jq: curl -s https://api.github.com/users/octocat | jq '.name, .bio'. The -s flag silences curl progress output. You can use any jq filter to extract, transform, or format the API response. For authenticated APIs, add headers: curl -s -H "Authorization: Bearer TOKEN" https://api.example.com/data | jq '.results[]'.

Bookmark this tutorial and come back whenever you need a jq reference. For working with JSON data in the browser, try our online tools below.

Try the JSON Formatter → | Try the JSON Viewer →

𝕏 Twitterin LinkedIn
Was this helpful?

Stay Updated

Get weekly dev tips and new tool announcements.

No spam. Unsubscribe anytime.

Try These Related Tools

{ }JSON Formatter🌳JSON Viewer / Tree>>cURL to Code Converter

Related Articles

curl Command Cheat Sheet: 50+ Examples for API Testing

The ultimate curl cheat sheet with 50+ copy-paste examples. GET, POST, headers, auth, file uploads, debugging, and converting curl to Python/JavaScript/Go.

JSON Formatter & Validator: Format, Beautify, and Fix JSON Online

Free online JSON formatter and validator. Pretty print JSON, find syntax errors, and learn JSON best practices with code examples in JavaScript and Python.