The AWS CLI's default output is JSON, and jq is the standard command-line tool for slicing, filtering, and reshaping it. This page covers jq filters against real AWS CLI and SDK-produced JSON, and where it overlaps with the CLI's own --query/JMESPath.
A common task: list the IDs and states of only the running EC2 instances, then feed the IDs into another command.
# Filter with jq's select(), then project to just the IDaws ec2 describe-instances --output json \ | jq -r '.Reservations[].Instances[] | select(.State.Name == "running") | .InstanceId'
# Reshape into a compact object per instanceaws ec2 describe-instances --output json \ | jq '.Reservations[].Instances[] | {id: .InstanceId, state: .State.Name, type: .InstanceType}'
# Feed jq's output straight into another aws commandfor id in $(aws ec2 describe-instances --output json \ | jq -r '.Reservations[].Instances[] | select(.State.Name=="stopped") | .InstanceId'); do echo "Stopped instance: $id"done
What this demonstrates:
select() filters elements by a condition, similar to JMESPath's [?...] filter syntax.
jq -r (raw output) is what you want when piping a value into a shell loop or another command; without -r you get a quoted JSON string like "i-0123...".
{key: .Path} builds a new object shape, the jq equivalent of a JMESPath multiselect hash.
The same JSON your SDK code would parse into a dict or a typed object is exactly what jq sees on the wire.
The AWS CLI has its own built-in filter language, JMESPath, exposed as --query and covered in depth on CLI Output Formats & --query/JMESPath. jq is a separate, general-purpose tool that happens to be excellent at the same job.
--query (JMESPath)
jq
Built into the CLI
Yes, no install needed
No, separate binary
Works on any JSON
No, only CLI command output
Yes, any JSON file or stream
Filtering by condition
[?State.Name=='running']
select(.State.Name == "running")
String/math functions
Limited JMESPath function set
Full expression language
Learning curve
Small, AWS-specific
Larger, but transfers to any JSON task
Both run entirely client-side, after the AWS API has already returned the full response - neither reduces what AWS sends over the wire. For that, use the CLI's own --filters or a request-level filter parameter where the API supports one.
A practical rule: reach for --query first since it needs nothing extra installed, and reach for jq when the transform gets complex enough that JMESPath becomes awkward, or when you are working with JSON that never came from the CLI at all.
Forgetting --output json - jq cannot parse the CLI's table or text output. Fix: always pass --output json (or set it as your profile default) before piping to jq.
Quoted strings breaking a shell loop - Without -r, jq prints "i-0123abc" with quotes, which then gets treated as a literal quoted string downstream. Fix: use jq -r whenever the result feeds into another shell command.
Confusing jq's select with JMESPath's [?...] - The syntax looks similar but is not interchangeable between the two tools. Fix: keep --query expressions and jq filters in separate mental buckets; do not paste one into the other.
Assuming jq reduces AWS billing or data transfer - Like --query, it runs after the full response has already arrived. Fix: use server-side filtering (a --filters flag or API FilterExpression) to actually cut what AWS returns.
Missing jq on a fresh machine - Unlike --query, jq is a separate binary that is not bundled with the AWS CLI. Fix: install it explicitly (brew install jq, apt-get install jq), and do not assume CI images have it preinstalled.
Iterating a null field - .Reservations[].Instances[] throws Cannot iterate over null if a key is missing from the response. Fix: guard with // [], e.g. (.Reservations // [])[].
A general-purpose command-line JSON processor. It reads JSON from stdin or a file and lets you filter, transform, and reshape it with a small expression language.
Is jq part of the AWS CLI?
No. The AWS CLI ships its own filter language, JMESPath, via --query. jq is a separate tool you install yourself, and it works on any JSON, not just AWS output.
Should I use jq or --query?
Use --query first, since it needs no extra install and covers most filtering needs. Reach for jq when you need something JMESPath cannot express, or you are working with JSON that did not come from the CLI.
Why does jq print quotes around my value?
By default jq always outputs valid JSON, so a single string result is still wrapped in quotes. Add -r (raw output) to print it as plain text instead.
Does jq reduce how much data AWS sends back?
No. Like --query, jq filters the response after it has already fully arrived. Use a server-side filter parameter on the API call itself to actually reduce data transfer.
Can jq parse output from my boto3 or SDK v3 code?
Yes, as long as the code writes valid JSON, whether that is to stdout, a file, or a debug log. jq does not care where the JSON came from.
How do I filter by a field's value in jq?
Use select(): .Items[] | select(.Status == "ACTIVE").
Why does my jq filter fail with "Cannot iterate over null"?
A key you expected to be an array is missing or null in the response. Guard it with // [], for example (.Reservations // [])[].
Is jq installed by default on Linux or macOS?
Usually not. Install it with your package manager (apt-get install jq, brew install jq) and do not assume it is present on a fresh machine or CI image.