Skip to content

S3

Amazon Simple Storage Service for storing and retrieving any amount of data from anywhere.

Protocol: RestXmlSigning name: s3Persistent: Yes (metadata only — object data is not persisted across restarts)

Quick Start

Create a bucket, upload a file, and download it:

bash
# Create a bucket
curl -s -X PUT http://localhost:4566/my-bucket \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/s3/aws4_request, SignedHeaders=host, Signature=fake"

# Upload an object
curl -s -X PUT http://localhost:4566/my-bucket/hello.txt \
  -H "Content-Type: text/plain" \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/s3/aws4_request, SignedHeaders=host, Signature=fake" \
  -d "Hello, World!"

# Download the object
curl -s http://localhost:4566/my-bucket/hello.txt \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/s3/aws4_request, SignedHeaders=host, Signature=fake"

# List objects in bucket
curl -s "http://localhost:4566/my-bucket?list-type=2" \
  -H "Authorization: AWS4-HMAC-SHA256 Credential=test/20260421/us-east-1/s3/aws4_request, SignedHeaders=host, Signature=fake"

Configuration

S3 state is global per account — it does not vary by region. All buckets are visible regardless of the region in the request.

Use forcePathStyle: true in your SDK client to use path-style URLs (/bucket/key) instead of virtual-hosted style (bucket.localhost/key).

Operations

Bucket Operations

OperationDescription
ListBucketsList all buckets. Returns Buckets list with Name and CreationDate. No input required
CreateBucketCreate a new bucket. Input: bucket name in URL path, optional CreateBucketConfiguration XML (for non-us-east-1 regions). Returns empty CreateBucketResult
DeleteBucketDelete a bucket. Must be empty first (no objects). Input: bucket name in URL path
HeadBucketCheck if a bucket exists. Returns 200 (exists) or 404 (not found). No body returned
GetBucketLocationGet the bucket's region. Returns LocationConstraint (empty string for us-east-1)
PutBucketVersioningEnable or suspend versioning. Input: VersioningConfiguration XML with Status: Enabled/Suspended
GetBucketVersioningGet versioning configuration
PutBucketTaggingSet bucket tags. Input: Tagging XML with TagSet
GetBucketTaggingGet bucket tags. Returns TagSet
DeleteBucketTaggingRemove all bucket tags
PutBucketPolicySet a bucket policy (JSON). Input: raw JSON policy body
GetBucketPolicyGet bucket policy (raw JSON)
DeleteBucketPolicyRemove bucket policy
PutBucketCorsSet CORS configuration. Input: CORSConfiguration XML
GetBucketCorsGet CORS configuration
DeleteBucketCorsRemove CORS configuration
PutBucketNotificationConfigurationConfigure S3 event notifications (SQS, SNS, Lambda)
GetBucketNotificationConfigurationGet event notification config

ACL Operations

OperationDescription
GetBucketAclGet the access control list for a bucket. Returns Owner and Grants list
PutBucketAclSet the access control list for a bucket. Input: AccessControlPolicy XML or a canned ACL header
GetObjectAclGet the ACL for an object. Returns Owner and Grants list

Lifecycle Operations

OperationDescription
GetBucketLifecycleConfigurationGet lifecycle rules for a bucket. Returns Rules list
PutBucketLifecycleConfigurationSet lifecycle rules. Input: LifecycleConfiguration XML with Rule elements
DeleteBucketLifecycleConfigurationRemove all lifecycle rules from a bucket

Encryption Operations

OperationDescription
GetBucketEncryptionGet the default server-side encryption configuration for a bucket
PutBucketEncryptionSet the default encryption. Input: ServerSideEncryptionConfiguration XML
DeleteBucketEncryptionRemove the default encryption configuration

Logging Operations

OperationDescription
GetBucketLoggingGet the logging configuration for a bucket. Returns LoggingEnabled element if configured
PutBucketLoggingSet the logging configuration. Input: BucketLoggingStatus XML

Object Operations

OperationDescription
PutObjectUpload an object. Input: PUT /{bucket}/{key}, body is object data, Content-Type header sets MIME type. Returns: ETag header
GetObjectDownload an object. Input: GET /{bucket}/{key}, optional Range header for partial reads. Returns: object body with Content-Type, ETag, Content-Length headers
HeadObjectGet object metadata without downloading the body. Returns headers only
DeleteObjectDelete an object. Input: DELETE /{bucket}/{key}. Returns 204 No Content
CopyObjectCopy an object within or between buckets. Input: PUT /{dest-bucket}/{dest-key} with x-amz-copy-source: /{src-bucket}/{src-key} header
ListObjectsV2List objects with optional prefix and delimiter. Input: GET /{bucket}?list-type=2&prefix=...&delimiter=/&max-keys=1000. Returns: Contents list, CommonPrefixes (virtual folders)
DeleteObjectsBatch delete objects. Input: POST /{bucket}?delete with Delete XML listing keys. Returns: Deleted and Error lists
PutObjectTaggingSet object tags. Input: PUT /{bucket}/{key}?tagging with Tagging XML
GetObjectTaggingGet object tags
DeleteObjectTaggingRemove object tags

Multipart Upload

OperationDescription
CreateMultipartUploadInitiate a multipart upload. Returns UploadId
UploadPartUpload a part. Input: PUT /{bucket}/{key}?partNumber={N}&uploadId={id}, body is part data. Returns ETag
CompleteMultipartUploadComplete the upload. Input: POST /{bucket}/{key}?uploadId={id} with CompleteMultipartUpload XML listing all parts and their ETags
AbortMultipartUploadCancel an in-progress upload. Input: DELETE /{bucket}/{key}?uploadId={id}
ListMultipartUploadsList in-progress uploads for a bucket
ListPartsList uploaded parts for a multipart upload

SDK Example

typescript
import {
  S3Client,
  CreateBucketCommand,
  PutObjectCommand,
  GetObjectCommand,
  ListObjectsV2Command,
  DeleteObjectCommand,
  CopyObjectCommand,
} from '@aws-sdk/client-s3';
import { Readable } from 'stream';

const s3 = new S3Client({
  region: 'us-east-1',
  endpoint: 'http://localhost:4566',
  credentials: { accessKeyId: 'test', secretAccessKey: 'test' },
  forcePathStyle: true, // Required for AWSim path-style URLs
});

// Create bucket
await s3.send(new CreateBucketCommand({ Bucket: 'my-bucket' }));

// Upload text
await s3.send(new PutObjectCommand({
  Bucket: 'my-bucket',
  Key: 'config/settings.json',
  Body: JSON.stringify({ debug: true, version: '1.0.0' }),
  ContentType: 'application/json',
}));

// Upload binary
import { readFileSync } from 'fs';
await s3.send(new PutObjectCommand({
  Bucket: 'my-bucket',
  Key: 'images/logo.png',
  Body: readFileSync('logo.png'),
  ContentType: 'image/png',
}));

// Download and read
const response = await s3.send(new GetObjectCommand({
  Bucket: 'my-bucket',
  Key: 'config/settings.json',
}));
const text = await response.Body?.transformToString();
console.log(JSON.parse(text!));

// List objects with prefix
const { Contents, CommonPrefixes } = await s3.send(new ListObjectsV2Command({
  Bucket: 'my-bucket',
  Prefix: 'config/',
  Delimiter: '/',
}));
console.log('Objects:', Contents?.map(o => o.Key));

// Copy object
await s3.send(new CopyObjectCommand({
  Bucket: 'my-bucket',
  Key: 'config/settings-backup.json',
  CopySource: '/my-bucket/config/settings.json',
}));

// Delete object
await s3.send(new DeleteObjectCommand({
  Bucket: 'my-bucket',
  Key: 'config/settings-backup.json',
}));

CLI Example

bash
# Bucket operations
aws --endpoint-url http://localhost:4566 s3 mb s3://my-bucket
aws --endpoint-url http://localhost:4566 s3 ls

# Object operations
aws --endpoint-url http://localhost:4566 s3 cp file.txt s3://my-bucket/file.txt
aws --endpoint-url http://localhost:4566 s3 cp s3://my-bucket/file.txt ./downloaded.txt
aws --endpoint-url http://localhost:4566 s3 ls s3://my-bucket/
aws --endpoint-url http://localhost:4566 s3 rm s3://my-bucket/file.txt

# Sync a directory
aws --endpoint-url http://localhost:4566 s3 sync ./dist s3://my-bucket/dist/

# Low-level API access
aws --endpoint-url http://localhost:4566 s3api put-object \
  --bucket my-bucket \
  --key data/record.json \
  --body record.json \
  --content-type application/json

aws --endpoint-url http://localhost:4566 s3api list-objects-v2 \
  --bucket my-bucket \
  --prefix data/ \
  --max-keys 100

Event Notifications

S3 can notify SQS queues, SNS topics, or Lambda functions when objects are created or deleted. See Cross-Service Integrations.

ACL Example

bash
# Get bucket ACL
aws --endpoint-url http://localhost:4566 s3api get-bucket-acl --bucket my-bucket

# Get object ACL
aws --endpoint-url http://localhost:4566 s3api get-object-acl \
  --bucket my-bucket \
  --key my-object.txt

Lifecycle Example

bash
# Put lifecycle configuration
aws --endpoint-url http://localhost:4566 s3api put-bucket-lifecycle-configuration \
  --bucket my-bucket \
  --lifecycle-configuration '{"Rules":[{"ID":"expire-old","Status":"Enabled","Expiration":{"Days":30},"Filter":{"Prefix":"tmp/"}}]}'

# Get lifecycle configuration
aws --endpoint-url http://localhost:4566 s3api get-bucket-lifecycle-configuration \
  --bucket my-bucket

Encryption Example

bash
# Enable AES-256 default encryption
aws --endpoint-url http://localhost:4566 s3api put-bucket-encryption \
  --bucket my-bucket \
  --server-side-encryption-configuration \
  '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}'

# Get encryption configuration
aws --endpoint-url http://localhost:4566 s3api get-bucket-encryption --bucket my-bucket

Behavior Notes

  • Object data is stored in memory; object metadata (key, size, ETag, content-type) is persisted across restarts but object body data is lost on restart.
  • Presigned URLs are not supported.
  • Bucket ACLs and object ACLs are accepted and stored but not enforced — all objects are accessible to any caller in AWSim.
  • Lifecycle rules are accepted and stored but items are not automatically expired or transitioned.
  • Encryption configuration is accepted and stored but objects are not actually encrypted at rest in AWSim.
  • Logging configuration is accepted and stored but no log delivery occurs in AWSim.
  • Object versioning is tracked (VersionId is returned) but GetObject always returns the latest version.
  • ListObjectsV2 supports Prefix filtering and Delimiter for virtual folder grouping (CommonPrefixes).
  • The forcePathStyle: true SDK option is required — virtual-hosted style (bucket.localhost:4566) is not recommended for local development.

Released under MIT / Apache-2.0 License