JMESPath queries make AWS CLI output easier to read and safer to reuse. Pulling only the needed fields keeps interactive checks shorter in the terminal and gives later shell steps one exact scalar, filtered list, or labeled object instead of an entire API payload.
The --query option applies a JMESPath expression after the AWS CLI receives the service response. That expression can project values out of lists, build new objects with custom labels, filter items with comparisons, and run functions such as sort_by() or length() before the chosen output format is rendered.
The examples below use a Linux or macOS shell, so the whole query stays inside single quotes while JMESPath string and numeric literals inside filters use backticks. While shaping or debugging an expression, prefer json or yaml output because current AWS CLI documentation warns that --output text paginates first and then evaluates the query once per page, which can produce repeated or unexpected matches on larger responses.
Steps to use JMESPath queries in AWS CLI:
- Inspect the response shape first so the top-level list names and field names are known before writing the query.
$ aws ec2 describe-regions --generate-cli-skeleton output { "Regions": [ { "OptInStatus": "OptInStatus", "Geography": [ { "Name": "Name" } ], "RegionName": "RegionName", "Endpoint": "Endpoint" } ] }--generate-cli-skeleton output renders a sample response locally without signing a live service request, which is useful for learning the response layout before running a real query.
- Project one field out of every item in a list when only a single value from each record is needed.
$ aws ec2 describe-regions \ --query 'Regions[].RegionName' \ --output json [ "us-east-1", "us-east-2", "us-west-1", "us-west-2" ]The list[].field pattern is the fastest way to turn a list of large objects into a simple list of identifiers. The live Region list varies by account and by which Regions are enabled.
- Build a smaller labeled object when several fields must stay together in a cleaner result.
$ aws ec2 describe-regions --generate-cli-skeleton output \ --query 'Regions[].{Region:RegionName,OptIn:OptInStatus}' \ --output json [ { "Region": "RegionName", "OptIn": "OptInStatus" } ]Multi-select hashes such as {Region:RegionName,OptIn:OptInStatus} keep only the chosen fields and rename them into keys that are easier to reuse in scripts, notes, or follow-up commands.
- Filter list items with a comparison inside [? ... ] when only matching records should remain.
$ aws ec2 describe-regions --all-regions \ --query 'Regions[?OptInStatus==`opt-in-not-required`].RegionName' \ --output json [ "us-east-1", "us-east-2", "us-west-1", "us-west-2" ]String and numeric literals inside a filter use backticks such as `opt-in-not-required` or `50`. Keep the entire query in single quotes on Linux and macOS so the shell passes those characters through unchanged.
- Pipe one intermediate result into a second expression when the first part creates a list that still needs one final selection.
$ aws ec2 describe-regions --generate-cli-skeleton output \ --query 'Regions[].RegionName | [0]' \ --output text RegionName
The pipe operator | stops the first projection and hands its result to the next expression, which is useful for taking one item, slicing a sorted list, or applying a final shape after filtering.
- Count matching records with length() when the total matters more than the raw list.
$ aws ec2 describe-volumes \ --filters "Name=status,Values=available" \ --query 'length(Volumes[?Iops > `1000`])' \ --output json 3
length() is useful for quick inventory checks, thresholds, and scripts that only need one number back. The returned total depends on the current account inventory.
- Sort a list with sort_by() when the newest, oldest, or otherwise ordered record must be selected from a larger result.
$ aws ec2 describe-images \ --owners amazon \ --filters "Name=name,Values=amzn*gp2" "Name=virtualization-type,Values=hvm" "Name=root-device-type,Values=ebs" \ --query 'sort_by(Images, &CreationDate)[-1].ImageId' \ --output text ami-00ced3122871a4921
The &CreationDate expression tells sort_by() which field to compare. The final AMI ID varies as the published image catalog changes.
- Combine service-side filters with --query on larger responses so the service returns less data before the CLI reshapes the final result.
$ aws ec2 describe-volumes \ --filters "Name=availability-zone,Values=us-west-2a" "Name=status,Values=attached" \ --query 'Volumes[?Size > `50`].{Id:VolumeId,Size:Size,Type:VolumeType}' \ --output json [ { "Id": "vol-0be9bb0bf12345678", "Size": 80, "Type": "gp2" } ]Current AWS CLI guidance states that server-side filters run first and --query performs the client-side shaping afterward, which reduces the response size before the JMESPath pass.
- Switch to --output text only after the query already returns the exact scalar or flat list required by the next shell step.
$ aws sts get-caller-identity \ --query Account \ --output text 123456789012
With --output text, the AWS CLI paginates first and evaluates the query once per page, so use json or yaml while developing the expression and reserve text output for the final narrowed result.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
