← All articles

jq Tutorial: Filter and Transform JSON

A practical jq tutorial: install it, pretty-print and minify, select fields, filter arrays with select, transform with map, plus copy-paste command recipes.

jq is the standard command-line tool for slicing, filtering, and transforming JSON. It turns one-liners into a powerful query language for API responses, log files, and config. This tutorial covers installation, the core filters you'll use every day, and a set of copy-paste recipes for the most common real-world tasks.

What Is jq?

jq reads JSON from a file or standard input, applies a filter, and writes JSON (or raw text) to standard output. It pretty-prints by default and never sends your data anywhere — it's a local binary, ideal for sensitive payloads.

Installing jq

# macOS
brew install jq

# Debian / Ubuntu
sudo apt-get install jq

# Windows (winget or choco)
winget install jqlang.jq

# Verify
jq --version

The Identity Filter: Pretty-Print Anything

The simplest filter, ., returns the input unchanged — which makes jq an instant formatter:

# Pretty-print a file
jq . data.json

# Pretty-print a curl response
curl -s https://api.example.com/users | jq .

# Minify instead (compact output)
jq -c . data.json

Selecting Fields

Drill into objects with .key, and into arrays with []:

echo '{"user":{"name":"Ada","age":36}}' | jq '.user.name'
# "Ada"

# All elements of an array
echo '[{"id":1},{"id":2}]' | jq '.[]'
# {"id":1}
# {"id":2}

# One field from every array element
echo '[{"id":1,"name":"Ada"},{"id":2,"name":"Bob"}]' | jq '.[].name'
# "Ada"
# "Bob"

# Strip the JSON quotes with -r (raw output)
jq -r '.[].name' users.json

Filtering with select

# Keep only objects matching a condition
echo '[{"name":"Ada","active":true},{"name":"Bob","active":false}]' \
  | jq '.[] | select(.active == true)'
# {"name":"Ada","active":true}

# Numeric comparison
jq '.[] | select(.age > 30)' users.json

Transforming with map and Object Construction

# Reshape every element into a new object
echo '[{"id":1,"name":"Ada","email":"a@x.com"}]' \
  | jq 'map({ userId: .id, label: .name })'
# [{"userId":1,"label":"Ada"}]

# Pull a flat list of values
jq '[.[].email]' users.json     # ["a@x.com", ...]

# Pipe filters together with |
jq '.items | map(.price) | add' order.json   # sum of all prices

Common Recipes

TaskCommand
Pretty-printjq . file.json
Minifyjq -c . file.json
Get one fieldjq '.data.token' resp.json
Raw string (no quotes)jq -r '.token' resp.json
Count array itemsjq '. | length' list.json
Keys of an objectjq 'keys' obj.json
Filter rowsjq '.[] | select(.active)'
Sort by a fieldjq 'sort_by(.age)'
Sum a fieldjq '[.[].amount] | add'
Sort object keysjq --sort-keys . file.json
Validate (exit code)jq empty file.json

Reshaping Objects: to_entries / from_entries

The two most useful object-shape transformers in jq:

# Rename every key (lowercase here)
echo '{"Name":"Ada","Active":true}' \
  | jq 'with_entries(.key |= ascii_downcase)'
# → {"name":"Ada","active":true}

# Drop keys whose value is null
jq 'with_entries(select(.value != null))' file.json

# Object ⇄ array of pairs
jq 'to_entries' file.json     # → [{"key":"name","value":"Ada"}, ...]
jq 'from_entries' pairs.json  # → {"name":"Ada", ...}

Interpolation and Output Formats: \(.x), @csv, @json, @base64

jq has string interpolation and built-in format strings for turning JSON into other formats:

# String interpolation inside a quoted string
jq -r '"\(.user) bought \(.items|length) items"' order.json

# CSV row per object
jq -r '.[] | [.id, .name, .total] | @csv' orders.json

# Inline-JSON for shells (escaped string literal)
jq -r '.user | @json' record.json

# Base64-encode a value (handy for tokens / data URIs)
jq -r '.payload | @base64' message.json
# Decode side: jq accepts @base64d in newer versions

Validating JSON with jq

Because jq exits non-zero on invalid input, jq empty file.json is a clean validity check for scripts and CI — see How to Validate JSON for more validation approaches.

When a Browser Tool Is Faster

jq shines in scripts and pipelines, but for a quick one-off — pretty-printing a pasted response, inspecting an unfamiliar structure, or repairing broken JSON — a browser tool needs no installation and no shell escaping:

Frequently Asked Questions

How do I pretty-print JSON with jq?

Run jq . file.json — the identity filter . returns the input and jq formats it by default. Use -c for compact output instead.

How do I extract a single field with jq?

Use a path filter like jq '.data.token', and add -r for raw output if you want the value without surrounding quotes.

How do I filter a JSON array with jq?

Iterate with .[] and apply select(), e.g. jq '.[] | select(.active == true)'.

Can jq validate JSON?

Yes — jq empty file.json parses the input and exits non-zero if it's invalid, making it handy in CI. For details see How to Validate JSON.

Keep Going