Amazon Simple Storage Service (S3) is object storage built for unlimited scale. Store images, backups, logs, data lakes, and static websites — S3 handles 100 million requests per second across AWS globally.

Core Concepts

Concept Description
Bucket Global namespace container (name must be unique worldwide)
Object File + metadata, up to 5 TB
Key Object path within bucket (images/logo.png)
Storage Class Cost/availability tier (Standard, IA, Glacier)
Region Bucket is created in one region (except CloudFront origin)

Create a Bucket and Upload

  # Create bucket (name must be globally unique)
aws s3 mb s3://my-company-app-assets-2024 --region us-east-1

# Upload a file
aws s3 cp ./logo.png s3://my-company-app-assets-2024/images/logo.png

# Upload directory recursively
aws s3 sync ./dist s3://my-company-app-assets-2024/ --delete

# List objects
aws s3 ls s3://my-company-app-assets-2024/ --recursive --human-readable
  

Storage Classes Comparison

Class Durability Access Pattern Retrieval Cost
Standard 99.999999999% Frequent Instant Highest storage
Standard-IA 99.999999999% Infrequent Instant Lower storage, retrieval fee
One Zone-IA 99.5% (single AZ) Infrequent, recreatable Instant Cheapest IA
Glacier Instant 99.999999999% Archive, instant access Instant Archive pricing
Glacier Flexible 99.999999999% Archive Minutes–hours Very low storage
Glacier Deep Archive 99.999999999% Long-term archive 12–48 hours Lowest storage
  # Upload directly to Intelligent-Tiering (auto-moves between tiers)
aws s3 cp report.pdf s3://my-bucket/archives/ \
    --storage-class INTELLIGENT_TIERING
  

Versioning and MFA Delete

Protect against accidental deletion:

  aws s3api put-bucket-versioning \
    --bucket my-company-app-assets-2024 \
    --versioning-configuration Status=Enabled

# List all versions of an object
aws s3api list-object-versions \
    --bucket my-company-app-assets-2024 \
    --prefix images/logo.png
  

Lifecycle Policies

Automate transitions and expiration:

  {
    "Rules": [{
        "ID": "MoveLogsToGlacier",
        "Status": "Enabled",
        "Filter": {"Prefix": "logs/"},
        "Transitions": [{
            "Days": 30,
            "StorageClass": "STANDARD_IA"
        }, {
            "Days": 90,
            "StorageClass": "GLACIER"
        }],
        "Expiration": {"Days": 365}
    }]
}
  
  aws s3api put-bucket-lifecycle-configuration \
    --bucket my-company-app-assets-2024 \
    --lifecycle-configuration file://lifecycle.json
  

Security Best Practices

Block Public Access (Default Since 2023)

  aws s3api put-public-access-block \
    --bucket my-company-app-assets-2024 \
    --public-access-block-configuration \
        BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
  

Bucket Policy (CloudFront OAC Example)

  {
    "Version": "2012-10-17",
    "Statement": [{
        "Sid": "AllowCloudFrontOAC",
        "Effect": "Allow",
        "Principal": {"Service": "cloudfront.amazonaws.com"},
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::my-company-app-assets-2024/*",
        "Condition": {
            "StringEquals": {
                "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1234567890"
            }
        }
    }]
}
  

Encryption

  # Default encryption (SSE-S3 or SSE-KMS)
aws s3api put-bucket-encryption \
    --bucket my-company-app-assets-2024 \
    --server-side-encryption-configuration '{
        "Rules": [{
            "ApplyServerSideEncryptionByDefault": {
                "SSEAlgorithm": "aws:kms",
                "KMSMasterKeyID": "arn:aws:kms:us-east-1:123:key/xxx"
            }
        }]
    }'
  

Static Website Hosting

  # Enable website hosting
aws s3 website s3://my-company-app-assets-2024/ \
    --index-document index.html \
    --error-document error.html

# Sync React/Vue build output
npm run build
aws s3 sync ./build s3://my-company-app-assets-2024/ \
    --cache-control "max-age=31536000" \
    --exclude "index.html"
aws s3 cp ./build/index.html s3://my-company-app-assets-2024/index.html \
    --cache-control "no-cache"
  

In production, front CloudFront for HTTPS, custom domain, and edge caching.

Presigned URLs

Grant temporary access without making objects public:

  # URL valid for 1 hour
aws s3 presign s3://my-bucket/private/report.pdf --expires-in 3600
  
  import boto3
s3 = boto3.client('s3')
url = s3.generate_presigned_url(
    'get_object',
    Params={'Bucket': 'my-bucket', 'Key': 'private/report.pdf'},
    ExpiresIn=3600
)
  

S3 Event Notifications

Trigger Lambda, SQS, or SNS on object events:

  aws s3api put-bucket-notification-configuration \
    --bucket my-bucket \
    --notification-configuration '{
        "LambdaFunctionConfigurations": [{
            "LambdaFunctionArn": "arn:aws:lambda:us-east-1:123:function:ProcessUpload",
            "Events": ["s3:ObjectCreated:*"],
            "Filter": {"Key": {"FilterRules": [{"Name": "prefix", "Value": "uploads/"}]}}
        }]
    }'
  

Real-World Scenario: Media Platform

Bucket Purpose Class Lifecycle
media-uploads User uploads Standard Delete incomplete multipart after 7 days
media-processed Transcoded video Standard Move to IA after 90 days
media-archive Old content Glacier 7-year retention for compliance
app-logs Access logs Standard Glacier after 30 days, delete after 1 year

S3 vs EBS vs EFS

Service Type Access Scale
S3 Object HTTP/API Unlimited objects
EBS Block Single EC2 instance Up to 64 TiB per volume
EFS File (NFS) Multiple EC2 instances Petabyte scale

Common Mistakes

  1. Public buckets — verify Block Public Access and bucket policies
  2. No versioning on critical data — enable versioning for production buckets
  3. Ignoring lifecycle rules — old logs in Standard class waste money
  4. Sync without --delete — stale files remain after redeploys
  5. Large number of small objects — consider packing into larger files or using S3 Express One Zone for high-throughput

Troubleshooting

Issue Cause Fix
403 Forbidden IAM or bucket policy Check policy, Block Public Access, object ACLs
NoSuchBucket Wrong region or name S3 is regional; verify bucket name and region
Slow uploads No transfer acceleration Enable S3 Transfer Acceleration for cross-region
High costs Standard class for archives Apply lifecycle rules to IA/Glacier
AccessDenied on CloudFront Missing OAC/OAI Update bucket policy for CloudFront distribution

Best Practices

  • Enable versioning and MFA Delete on production buckets
  • Use SSE-KMS for sensitive data with key rotation
  • Apply lifecycle policies from day one
  • Front public content with CloudFront + OAC
  • Use S3 Inventory for auditing object metadata at scale
  • Enable S3 Access Logging for security forensics
  • Use multipart upload for files > 100 MB

Next: RDS — Managed Databases.