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 --versionBasic 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"]'
# 42Array 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
# 3Constructing 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'
# 64. 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'
# "<script>alert(1)</script>"
# @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 256. 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
# 59. 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"
# success12. Cheat Sheet: Quick Reference
The most commonly used jq patterns at a glance. Bookmark this table for quick lookup.
| Pattern | Description | Example |
|---|---|---|
. | Identity (pretty-print) | jq '.' |
.field | Get object field | jq '.name' |
.a.b.c | Nested field access | jq '.user.address.city' |
.[n] | Array index | jq '.[0]' |
.[] | Iterate array/object values | jq '.users[]' |
.[m:n] | Array slice | jq '.[2:5]' |
| | Pipe (chain filters) | jq '.[] | .name' |
select() | Filter by condition | jq '.[] | select(.age>30)' |
map() | Transform array elements | jq 'map(.name)' |
sort_by() | Sort array by field | jq 'sort_by(.age)' |
group_by() | Group by field | jq 'group_by(.type)' |
unique_by() | Deduplicate by field | jq 'unique_by(.id)' |
keys | Get object keys | jq 'keys' |
values | Get object values | jq 'values' |
to_entries | Object to key-value pairs | jq 'to_entries' |
from_entries | Key-value pairs to object | jq 'from_entries' |
with_entries() | Transform entries in place | jq 'with_entries(.key|=ascii_upcase)' |
length | Array/object/string length | jq '.items | length' |
// | Alternative (default value) | jq '.x // "default"' |
del() | Delete key from object | jq 'del(.tmp)' |
add | Sum array / concat | jq '[.[] | .score] | add' |
flatten | Flatten nested arrays | jq 'flatten' |
@csv / @tsv | Format as CSV/TSV | jq -r '.[] | @csv' |
@base64 | Base64 encode | jq '.token | @base64' |
--arg k v | Pass string argument | jq --arg n "Alice" '.name==$n' |
-r | Raw output (no quotes) | jq -r '.name' |
-s | Slurp: read all inputs as array | jq -s 'add' |
-c | Compact output | jq -c '.' |
-e | Exit status based on output | jq -e '.ok' |
reduce | Accumulate values | jq '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.