aws ec2 describe-instances is an AWS CLI command that retrieves metadata for one or more EC2 instances, supporting server-side filtering, pagination, and JMESPath queries for automation and auditing.
aws ec2 describe-instances --filters Name=instance-type,Values=m5.large
Tested on Ubuntu 22.04 with Linux 5.15.x; verify against vendor docs for non-Debian distributions or older kernels.
Syntax
aws ec2 describe-instances
[--instance-ids <value>]
[--filters <value>]
[--dry-run | --no-dry-run]
[--include-managed-resources | --no-include-managed-resources]
[--max-items <value>]
[--page-size <value>]
[--starting-token <value>]
[--cli-input-json | --cli-input-yaml]
[--no-paginate]
[--query <value>]
[--output <value>]
[--region <value>]
[--profile <value>]
Options and Flags
| Flag | Type | Default | Description |
|---|---|---|---|
--instance-ids |
List of Strings | None | Filter by specific instance IDs. |
--filters |
List of Filter objects | None | Key-value pairs to narrow results (e.g., Name=instance-type,Values=t2.micro). |
--query |
JMESPath expression | Raw JSON | Extract specific fields; critical for scripting and reducing output. |
--output |
String | json | Format: json, text, table, yaml, yaml-stream. Use text for machine parsing. |
--max-items |
Integer | All | Max results per API call; used with pagination. |
--page-size |
Integer | 1000 | Page size for internal pagination; affects throttling. |
--dry-run |
Flag (bool) | false | Checks required IAM permissions without making changes. |
--no-paginate |
Flag (bool) | false | Disables automatic pagination; single API response. |
--region |
String | default | AWS Region endpoint for the call. |
--profile |
String | default | Named profile from credentials/config file. |
--cli-input-json |
String | None | Read inputs from a JSON file (complex filters). |
--debug |
Flag | false | Detailed debug logging for troubleshooting. |
Usage Examples
Example 1: List all running instances with their public IPs
aws ec2 describe-instances
--filters "Name=instance-state-name,Values=running"
--query "Reservations[*].Instances[*].{InstanceId:InstanceId,PublicIp:PublicIpAddress}"
--output table
Filters to running instances only, then uses JMESPath to project a concise table of instance IDs and public IPs. Ideal for quick inventory checks across an account.
Example 2: Retrieve tags from a specific instance
aws ec2 describe-instances
--instance-ids i-0abcd1234efgh5678
--query "Reservations[*].Instances[*].Tags"
--output json
Returns the full tag array for one instance. Use with jq to extract specific keys: aws ec2 describe-instances --instance-ids i-... --query "Reservations[*].Instances[*].Tags" | jq '.[][][] | select(.Key=="Name") | .Value'.
Example 3: Complex multi-filter with JSON file
# filters.json
# [
# {"Name": "instance-type", "Values": ["t2.micro","t3.micro"]},
# {"Name": "availability-zone", "Values": ["us-east-2c"]}
# ]
aws ec2 describe-instances
--filters file://filters.json
--query "Reservations[*].Instances[*].{InstanceId:InstanceId,Type:InstanceType,AZ:Placement.AvailabilityZone}"
--output table
For complex filter sets, store in a JSON file to avoid shell escaping issues. This example retrieves only t2.micro and t3.micro instances in us-east-2c and displays a custom table.
Example 4: Paginate through 5000+ instances
aws ec2 describe-instances
--max-items 1000
--page-size 200
--query "Reservations[*].Instances[*].InstanceId"
--output text
Use --max-items to control total results (1000 per call) and --page-size to reduce API throttling (200 per page). The CLI automatically handles the next token. To get all results, avoid --max-items unless you want to stop early.
Troubleshooting & Common Errors
| Error Message/Code | Root Cause | Resolution Command |
|---|---|---|
An error occurred (UnauthorizedOperation) ... not authorized to perform: ec2:DescribeInstances |
Missing IAM permission ec2:DescribeInstances on the resource. |
Attach the managed policy AmazonEC2ReadOnlyAccess or inline with Resource: "*". Verify via aws iam simulate-principal-policy --policy-source-arn arn:aws:iam::123456789012:user/youruser --action-names ec2:DescribeInstances |
InvalidInstanceID.NotFound: The instance ID 'i-xxxx' does not exist |
Instance ID is mistyped or belongs to a different region. | Confirm region with aws ec2 describe-regions and re-run with --region correct. Or double-check ID via console. |
An error occurred (RequestLimitExceeded) when calling the DescribeInstances operation |
API rate limit reached. | Reduce request frequency: --page-size 50 or implement jittered backoff. Use --no-paginate and handle pagination tokens manually. |
aws: error: argument --query: Invalid query |
JMESPath syntax error (e.g., unquoted backticks). | Wrap expression in double quotes when using backticks: --query "Reservations[*].Instances[*].Tags[?Key=='Name']" |
| Empty output (no results) with success code 0 | Filters too restrictive or wrong region/profile. | Simplify filters: first call without --filters. Verify region aws configure get region and profile aws sts get-caller-identity. |
Exit Codes
| Code | Meaning | Operational Impact |
|---|---|---|
| 0 | Success | Command completed as expected; output may be empty if no instances match filters. |
| 255 | General error (service, parsing, auth) | Check AWS credentials, network, or request syntax. Common for invalid instance IDs or malformed filters. No partial output. |
| 254 | API throttling / rate limit exceeded | Implement exponential backoff or reduce page size. The CLI may suggest retry with --no-paginate. |
| 250 | Invalid CLI input or option | Indicates malformed parameters (e.g., --filters without key-value pairs). Review help: aws ec2 describe-instances help. |
Closing Tip
Always pair --query with --output text in shell loops and scripts to avoid JSON parsing overhead, for example: for id in $(aws ec2 describe-instances --query "Reservations[*].Instances[*].[InstanceId]" --output text); do echo "$id"; done.
Multi-Cloud Comparison
| Feature | aws ec2 describe-instances | Azure equivalent | GCP equivalent |
|---|---|---|---|
| List all VMs | aws ec2 describe-instances |
az vm list |
gcloud compute instances list |
| Filter by name/tag | --filters "Name=tag:Name,Values=web" |
--query "[?tags.Name=='web']" |
--filter "name=web-*" |
| Filter by state | --filters "Name=instance-state-name,Values=running" |
--query "[?powerState=='running']" |
--filter "status=RUNNING" |
| Get specific fields | --query (JMESPath) |
--query (JMESPath) |
--format + --columns |
| Pagination handling | Automatic via --max-items, --starting-token |
Automatic via --max-items |
Manual via --page-size, --page-token |
Frequently Asked Questions
What is the difference between the `–filters` and `–query` flags?
Answer: `–filters` applies server-side filtering before the API returns data, reducing network payload.
Use `–filters` to minimize latency and cost on large environments. `–query` is useful for post-processing structured output. Example of server-side filter:
aws ec2 describe-instances --filters "Name=instance-state-name,Values=running"
Equivalent client-side query (less efficient):
aws ec2 describe-instances --query 'Reservations[].Instances[?State.Name==`running`]'
When should I use `–output json` vs `–output table`?
Answer: Use `–output json` for programmatic consumption, piping to `jq`, or automation.
Table truncates long strings and omits nested objects, while JSON preserves all data. Example table command:
aws ec2 describe-instances --query 'Reservations[*].Instances[*].[InstanceId,State.Name]' --output table
For JSON output feeding into jq:
aws ec2 describe-instances --output json | jq '.Reservations[].Instances[] | {id: .InstanceId, state: .State.Name}'
How do I fix “An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation”?
Answer: Attach an IAM policy granting `ec2:DescribeInstances` on the target resources.
Minimal policy statement:
{
"Effect": "Allow",
"Action": "ec2:DescribeInstances",
"Resource": "*"
}
For instance-profile based access, ensure the attached role has the permission. Test with:
aws sts get-caller-identity
Does `aws ec2 describe-instances` work on Azure or GCP?
Answer: No.
Multi-cloud equivalents:
Azure:
az vm list --output table
GCP:
gcloud compute instances list --format="table(name,zone,status)"
No cross-platform compatibility; each CLI is provider-specific.
What is the fastest way to list all running EC2 instances by name and instance ID?
Answer: Apply `–filters` for state=running, use `–query` to project the Name tag and InstanceId, and output as text for minimal parsing overhead.
Optimized command:
aws ec2 describe-instances
--filters "Name=instance-state-name,Values=running"
--query 'Reservations[*].Instances[*].[Tags[?Key==`Name`].Value|[0],InstanceId]'
--output text
The `–filters` reduces API response size; `–output text` avoids JSON/Table overhead, yielding sub-second execution on hundreds of instances.

Command Line Expert & Software Engineer
Welcome! I’m Thomas Heinrich, a software engineer and system administrator with a deep passion for the Command Line Interface (CLI). With years of experience navigating the terminal, building backend architectures, and automating server deployments, I created this space to share practical, real-world terminal knowledge.
Whether you are a beginner taking your first steps in a Linux environment or a seasoned DevOps engineer looking to optimize your deployment scripts, you will find actionable solutions here. My goal is to help you ditch the mouse, speed up your workflow, and harness the full power of the command line.