Skip to content
AWS core 4 min read

S3: Object Storage

Amazon Simple Storage Service (S3) is object storage built for the internet - virtually unlimited capacity, accessible over HTTPS, and the storage backbone behind countless applications. It stores anything from website assets and backups to data-lake analytics and machine-learning datasets.

Buckets and objects

S3 has a flat structure built from two concepts:

  • Bucket — a globally unique, region-scoped container for objects. The name must be unique across all of AWS.
  • Object — a file plus metadata, identified by a key (its full name). Keys can contain /, which the console renders as folders, but the namespace is actually flat - there are no real directories.

Objects can be up to 5 TB; use multipart upload for anything over 100 MB to improve throughput and resilience.

Durability and availability

S3 Standard is designed for eleven nines (99.999999999%) of durability - achieved by redundantly storing each object across multiple devices in multiple AZs within a Region. Availability (the SLA for access) is lower and varies by storage class, typically 99.9%-99.99%.

Durability is not backup. S3 protects against hardware failure, but a bad aws s3 rm or a compromised credential can still delete your data. Enable versioning and consider Object Lock for true protection.

Storage classes

Choosing the right class is the primary S3 cost lever. All offer the same 11-nines durability.

ClassBest forRetrievalRelative cost
StandardHot, frequently accessed dataInstantHighest
Intelligent-TieringUnknown/changing access patternsInstantAuto-optimized
Standard-IAInfrequent access, fast when neededInstant (+ fee)Lower
One Zone-IARe-creatable infrequent dataInstant (single AZ)Lower still
Glacier InstantArchive needing ms retrievalInstantLow
Glacier Flexible / Deep ArchiveLong-term archive, complianceMinutes to hoursLowest

Intelligent-Tiering is the safe default when you can’t predict access patterns - it moves objects between tiers automatically for a tiny monitoring fee and avoids retrieval surprises.

Versioning

Versioning keeps every version of an object, so overwrites and deletes are recoverable. A “delete” simply adds a delete marker; the prior versions remain.

aws s3api put-bucket-versioning \
  --bucket devcraftly-uploads \
  --versioning-configuration Status=Enabled

Versioning stores - and bills you for - every version. Without lifecycle rules to expire old versions, costs creep up silently over time.

Lifecycle policies

Lifecycle rules automate transitions between storage classes and expiration of objects or old versions.

{
  "Rules": [
    {
      "ID": "ArchiveThenDelete",
      "Status": "Enabled",
      "Filter": { "Prefix": "logs/" },
      "Transitions": [
        { "Days": 30, "StorageClass": "STANDARD_IA" },
        { "Days": 90, "StorageClass": "GLACIER" }
      ],
      "Expiration": { "Days": 365 }
    }
  ]
}

Bucket policies vs ACLs

Two mechanisms control access; modern practice is decisive about which to use.

MechanismGranularityRecommendation
Bucket policy (IAM-style JSON)Bucket / prefix / objectPreferred - expressive, auditable
ACL (legacy)Bucket / objectAvoid - disable via Object Ownership
IAM policyOn the principalUse for per-user/role access

Enable S3 Block Public Access at the account level and disable ACLs. The most common AWS data leak is an accidentally public bucket - block public access unless you have a deliberate, specific reason to allow it.

A bucket policy granting public read for a static site:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "PublicRead",
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::devcraftly-site/*"
  }]
}

Static website hosting

S3 can serve a static site directly, though pairing it with CloudFront adds HTTPS, caching, and a custom domain.

aws s3 website s3://devcraftly-site/ \
  --index-document index.html \
  --error-document 404.html

CLI upload example

# Sync a local build folder to a bucket, deleting removed files
aws s3 sync ./dist s3://devcraftly-site --delete

Output:

upload: dist/index.html to s3://devcraftly-site/index.html
upload: dist/assets/app.css to s3://devcraftly-site/assets/app.css
upload: dist/assets/app.js to s3://devcraftly-site/assets/app.js

Best Practices

  • Turn on Block Public Access and disable ACLs; control access with bucket and IAM policies.
  • Enable versioning plus lifecycle rules to expire old versions and control cost.
  • Use default encryption (SSE-S3 or SSE-KMS) on every bucket.
  • Front public content with CloudFront for HTTPS, caching, and lower egress cost.
  • Match data to the right storage class; use Intelligent-Tiering when access is unpredictable.
  • Enable access logging or CloudTrail data events for audit, and tag buckets for cost allocation.
Last updated June 1, 2026
Was this helpful?