aws s3 cp: Usage, Options & Common CI Errors
Copy files to and from S3 - one object, a tree, or a stream.
aws s3 cp copies a local file to S3, an S3 object to local, or between buckets. It is the workhorse for publishing build artifacts and pulling config in pipelines.
What it does
aws s3 cp <src> <dst> copies a single object by default; with --recursive it copies a whole directory tree. Either side may be a local path or an s3:// URI. It supports streaming with - (stdin/stdout), and flags for content type, cache control, and ACLs.
Common usage
# Upload a single file
aws s3 cp build.zip s3://my-bucket/releases/build.zip
# Download
aws s3 cp s3://my-bucket/config.json ./config.json
# Recursive upload of a directory
aws s3 cp ./dist s3://my-bucket/site --recursive
# Stream stdin into an object
cat report.txt | aws s3 cp - s3://my-bucket/report.txtCommon error in CI: AccessDenied / wrong content type
Uploads fail with "An error occurred (AccessDenied) when calling the PutObject operation" when the CI role lacks s3:PutObject on the bucket/prefix, or a bucket policy denies it. Fix: grant s3:PutObject (and s3:GetObject for downloads) scoped to the exact arn:aws:s3:::bucket/prefix/*. A subtler issue: files served from S3 get the wrong MIME type - set it explicitly with --content-type text/html (cp does not always infer it), or downstream browsers download instead of render your assets.
Key options
| Option | Purpose |
|---|---|
| --recursive | Copy a directory tree |
| --content-type | Set the object MIME type |
| --cache-control | Set Cache-Control metadata |
| --acl | Canned ACL (e.g. public-read) |
| --sse | Server-side encryption (AES256, aws:kms) |
| --exclude / --include | Filter which files copy |