Get last modified object from S3 using AWS CLI
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
To get the last modified object from an S3 bucket using the AWS CLI, use s3api list-objects-v2 with a JMESPath query that sorts by LastModified and selects the final element:
This returns a single JSON object with the key and timestamp of the most recently modified object in the bucket. The rest of this article covers prefix filtering, pagination for large buckets, downloading the result, and scripting the whole workflow.
Prerequisites
Before running these commands, ensure the AWS CLI is installed and configured:
The IAM principal you authenticate with needs at minimum the s3:ListBucket permission on the target bucket, and s3:GetObject if you intend to download the result.
Step 1: List Objects Sorted by LastModified
The core command uses the --query parameter to apply a JMESPath expression server-side:
Example output:
Understanding the JMESPath Expression
| Part | Purpose |
Contents | Selects the array of object metadata from the API response |
sort_by(@, &LastModified) | Sorts the array by the LastModified timestamp in ascending order |
[-1] | Selects the last (most recent) element |
.{Key: Key, ...} | Projects only the fields you want in the output |
Step 2: Filter by Prefix
Most real-world buckets organize objects under prefixes (pseudo-directories). To find the most recent object under a specific prefix:
The --prefix flag tells S3 to return only objects whose keys start with logs/production/, which dramatically reduces the response size for large buckets.
Step 3: Download the Most Recent Object
To download the object in a single pipeline, capture the key and pass it to s3 cp:
The --output text flag strips the JSON quotes so the key can be used directly in the s3 cp command.
Handling Large Buckets With Pagination
list-objects-v2 returns a maximum of 1,000 objects per request. For buckets with more objects, you need pagination. The --page-size parameter controls how many objects are requested per API call, and the --max-items parameter limits the total number of objects returned.
However, for finding the most recent object across the entire bucket, you need all objects. Use the --no-paginate flag or let the CLI paginate automatically:
For very large buckets (millions of objects), this approach becomes slow. A better strategy is to use S3 Inventory or narrow the search with a specific prefix.
Alternative: Using s3 ls With Sort
For a quick-and-dirty approach, you can use s3 ls combined with sort and tail:
This works because s3 ls output includes timestamps in a sortable format. However, it downloads all object listings as text, which is less efficient than the JMESPath approach for large buckets.
Scripting a Complete Workflow
Here is a complete bash script that finds and downloads the latest object, with error handling:
Using the Python SDK (boto3) Alternative
When the AWS CLI approach becomes unwieldy, the Python SDK offers more control:
This handles pagination automatically and avoids the JMESPath complexity. It is the better approach for production automation scripts.
Command Reference
| Task | Command |
| Latest object in bucket | aws s3api list-objects-v2 --bucket B --query "sort_by(Contents, &LastModified)[-1]" |
| Latest object under prefix | Add --prefix "path/" to the above |
| Latest key only (for scripting) | Add --query "sort_by(...)[-1].Key" --output text |
| Download latest object | Pipe the key into aws s3 cp |
| List all objects with timestamps | aws s3 ls s3://bucket/ --recursive |
| Count objects under prefix | aws s3api list-objects-v2 --bucket B --prefix P --query "length(Contents)" |
Common Pitfalls
Forgetting the --prefix filter on large buckets causes the CLI to enumerate every object, which can take minutes or hours and incur significant LIST API costs. Always scope the search to the narrowest prefix possible.
Assuming list-objects-v2 returns all objects in one call is incorrect for buckets with more than 1,000 objects. Without --no-paginate, the JMESPath query only operates on the first page of results, which may not contain the most recent object.
Using --query with sort_by on an empty prefix returns null when the bucket or prefix contains no objects. Scripts should check for null before attempting to download.
Confusing LastModified with creation time is a subtle issue. S3 updates LastModified when an object is overwritten, so the "most recently modified" object may not be the "newest" object by key name or logical sequence.
Not quoting the bucket name or prefix in scripts can cause word splitting issues in bash. Always use double quotes around variables.
Summary
- Use
aws s3api list-objects-v2with--query "sort_by(Contents, &LastModified)[-1]"to find the most recent object. - Add
--prefixto narrow the search to a specific path within the bucket. - Use
--output textwhen capturing the key for use in downstream commands likes3 cp. - For buckets with more than 1,000 objects, ensure pagination is handled with
--no-paginateor use the boto3 SDK. - Always check for empty results (
null) in scripts before attempting to process the key. - Prefer prefix filtering over full-bucket scans to control both latency and API costs.

