Objects
Upload, download, stat, copy, and delete objects.
Upload
aws s3api put-object \
--bucket my-bucket \
--key path/to/file.txt \
--body file.txt \
--profile liteio
{ "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"" }
The ETag is the MD5 of the body, quoted, exactly as the S3 spec wants it.
With metadata
User metadata rides along as x-amz-meta-* headers and comes back on GET and
HEAD:
aws s3api put-object \
--bucket my-bucket \
--key photo.jpg \
--body photo.jpg \
--content-type image/jpeg \
--metadata '{"author":"alice","project":"website"}' \
--profile liteio
With tags
aws s3api put-object \
--bucket my-bucket \
--key photo.jpg \
--body photo.jpg \
--tagging 'env=prod&project=website' \
--profile liteio
Presigned upload
Hand a time-limited PUT URL to a client that has no credentials:
aws s3 presign s3://my-bucket/upload.bin --expires-in 3600 --profile liteio
# Then, from anywhere:
curl -X PUT --upload-file upload.bin "$PRESIGNED_URL"
Download
aws s3api get-object \
--bucket my-bucket \
--key path/to/file.txt \
output.txt \
--profile liteio
A byte range
Useful for resuming a transfer or reading a slice of a large file. liteio
answers with 206 Partial Content and a Content-Range header:
aws s3api get-object \
--bucket my-bucket \
--key large-file.bin \
--range 'bytes=0-1048575' \
part0.bin \
--profile liteio
Conditionally
All four conditional headers work. Fetch only if the object changed:
aws s3api get-object \
--bucket my-bucket \
--key file.txt \
output.txt \
--if-none-match '"d41d8cd98f00b204e9800998ecf8427e"' \
--profile liteio
A matching If-None-Match returns 304 Not Modified. If-Match,
If-Modified-Since, and If-Unmodified-Since behave the same way they do on
AWS.
Stat (HEAD)
Metadata without the body:
aws s3api head-object --bucket my-bucket --key file.txt --profile liteio
{
"ContentType": "application/octet-stream",
"ContentLength": 1234,
"ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
"LastModified": "2026-06-10T12:00:00.000Z"
}
Delete
aws s3api delete-object --bucket my-bucket --key file.txt --profile liteio
With versioning on, this writes a delete marker. Pass --version-id to remove a
specific version for good.
Delete in bulk
Up to 1,000 keys in one round trip:
aws s3api delete-objects \
--bucket my-bucket \
--delete '{"Objects":[{"Key":"a.txt"},{"Key":"b.txt"},{"Key":"c.txt"}]}' \
--profile liteio
{
"Deleted": [
{ "Key": "a.txt" },
{ "Key": "b.txt" },
{ "Key": "c.txt" }
]
}
Copy
Server-side, within a bucket or across buckets, with no round trip through the client:
aws s3api copy-object \
--bucket dest-bucket \
--key new/path/file.txt \
--copy-source my-bucket/path/to/file.txt \
--profile liteio
{
"CopyObjectResult": {
"ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
"LastModified": "2026-06-10T12:01:00.000Z"
}
}
Object tags
aws s3api put-object-tagging \
--bucket my-bucket \
--key file.txt \
--tagging 'TagSet=[{Key=env,Value=prod}]' \
--profile liteio
aws s3api get-object-tagging --bucket my-bucket --key file.txt --profile liteio
aws s3api delete-object-tagging --bucket my-bucket --key file.txt --profile liteio