This page requires JavaScript to display.
S
Unpacking...
← Cloud Platforms
Cloud Platforms

Amazon S3 for Data Engineers

Buckets and keys, data-lake layout, CLI and boto3, storage classes and lifecycle, security and encryption, versioning and Object Lock, event notifications, performance and cost.

Contents
1. What Amazon S3 Is 2. Data Lake Layout 3. AWS CLI Essentials 4. S3 with Python (boto3) 5. Storage Classes & Lifecycle 6. Security: Access, Encryption & Governance 7. Versioning, Object Lock & Replication 8. Event Notifications 9. Performance & Cost 10. Common Interview Questions

1. What Amazon S3 Is

Amazon S3 (Simple Storage Service) is object storage: you store objects (files plus metadata) in buckets, addressed by a key such as raw/transactions/dt=2026-10-26/part-0001.parquet. It is the foundation of almost every AWS data lake: cheap, highly durable (designed for 11 nines), and read directly by Athena, Glue, EMR, Redshift Spectrum, SageMaker and Databricks.

ConceptDetail
BucketGlobally unique name, created in one region; holds unlimited objects
Key and prefixThere are no real folders: "raw/transactions/" is just a key prefix. Prefixes matter for performance, lifecycle rules and permissions
ConsistencyStrong read-after-write consistency for PUT, DELETE and LIST since December 2020
Object sizeSingle PUT up to 5 GB; larger objects (into the terabytes) need multipart upload
VersioningOptional: keeps every version of an object, protecting against overwrites and deletes
Durability vs availabilityDurability = not losing data (11 nines); availability = being able to read it now (99.9–99.99% depending on class)

2. Data Lake Layout

s3://acme-lake-prod/
├── raw/  # landing zone: files exactly as received (immutable)
│   └── transactions/source=upi/ingest_date=2026-10-26/upi_20261026_0001.json.gz
├── bronze/  # same data in an open table format (Delta / Iceberg), append-only
├── silver/                   # cleaned, deduplicated, conformed
│   └── transactions/dt=2026-10-26/part-00000.snappy.parquet
├── gold/                     # business aggregates, star schemas
└── _quarantine/              # records that failed validation

s3://acme-lake-prod-logs/  # access logs and query results in a separate bucket

3. AWS CLI Essentials

aws s3 mb s3://acme-lake-dev --region ap-south-1
aws s3 ls s3://acme-lake-dev/raw/transactions/ --recursive --human-readable --summarize
aws s3 cp ./txn.json.gz s3://acme-lake-dev/raw/transactions/ingest_date=2026-10-26/
aws s3 cp s3://acme-lake-dev/silver/ ./local/ --recursive --exclude "*" --include "*.parquet"
aws s3 sync ./exports/ s3://acme-lake-dev/raw/exports/ --delete  # mirror a folder
aws s3 mv s3://acme-lake-dev/raw/a.csv s3://acme-lake-dev/archive/a.csv
aws s3 rm s3://acme-lake-dev/tmp/ --recursive

aws s3api head-object --bucket acme-lake-dev --key raw/transactions/x.json.gz  # size, ETag, metadata
aws s3api list-object-versions --bucket acme-lake-dev --prefix silver/customers/
aws s3 presign s3://acme-lake-dev/reports/daily.csv --expires-in 3600  # temporary share link

4. S3 with Python (boto3)

import boto3
from boto3.s3.transfer import TransferConfig

s3 = boto3.client("s3")  # credentials from the IAM role / environment, never hard-coded

# upload with multipart for large files (parallel parts, automatic retries)
cfg = TransferConfig(multipart_threshold=64 * 1024 * 1024, max_concurrency=8)
s3.upload_file("big_extract.parquet", "acme-lake-dev", "raw/extracts/big_extract.parquet",
               Config=cfg, ExtraArgs={"ServerSideEncryption": "aws:kms"})

# list every object under a prefix (a single call returns at most 1,000 keys)
paginator = s3.get_paginator("list_objects_v2")
keys = [obj["Key"]
        for page in paginator.paginate(Bucket="acme-lake-dev", Prefix="raw/transactions/")
        for obj in page.get("Contents", [])]

# stream a large object line by line without loading it all into memory
body = s3.get_object(Bucket="acme-lake-dev", Key="raw/events/2026-10-26.jsonl")["Body"]
for line in body.iter_lines():
    process(line)

# write small results / markers
s3.put_object(Bucket="acme-lake-dev", Key="raw/transactions/dt=2026-10-26/_SUCCESS", Body=b"")

url = s3.generate_presigned_url("get_object", Params={"Bucket": "acme-lake-dev", "Key": "reports/daily.csv"},
                                ExpiresIn=3600)
# pandas / Parquet straight from S3 with the AWS SDK for pandas (awswrangler)
import awswrangler as wr

df = wr.s3.read_parquet("s3://acme-lake-dev/silver/transactions/", dataset=True,
                        partition_filter=lambda p: p["dt"] == "2026-10-26")
wr.s3.to_parquet(df, path="s3://acme-lake-dev/gold/daily_summary/", dataset=True,
                 partition_cols=["dt"], mode="overwrite_partitions")

5. Storage Classes & Lifecycle

ClassUseNotes
S3 StandardHot data, frequently readDefault; no retrieval fee
S3 Intelligent-TieringUnknown or changing access patternsMoves objects between tiers automatically; small monitoring fee per object
S3 Standard-IAInfrequently read, needs fast access30-day minimum, per-GB retrieval fee
S3 One Zone-IARe-creatable infrequent dataOne AZ only, cheaper
Glacier Instant RetrievalArchive read a few times a year, milliseconds90-day minimum
Glacier Flexible RetrievalArchive, minutes to hours to restore90-day minimum
Glacier Deep ArchiveLong-term retention (regulatory), hours to restoreCheapest; 180-day minimum
S3 Express One ZoneSingle-digit millisecond access for very hot dataDirectory buckets in one AZ; for latency-sensitive analytics/ML
{
  "Rules": [
    {
      "ID": "raw-tiering",
      "Filter": { "Prefix": "raw/" },
      "Status": "Enabled",
      "Transitions": [
        { "Days": 30,  "StorageClass": "STANDARD_IA" },
        { "Days": 180, "StorageClass": "GLACIER" }
      ],
      "Expiration": { "Days": 2555 },
      "NoncurrentVersionExpiration": { "NoncurrentDays": 30 },
      "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
    }
  ]
}
aws s3api put-bucket-lifecycle-configuration --bucket acme-lake-prod --lifecycle-configuration file://lifecycle.json

Always add AbortIncompleteMultipartUpload: failed multipart uploads leave invisible parts that you keep paying for.

6. Security: Access, Encryption & Governance

ControlRecommendation
Block Public AccessOn at the account level and for every bucket
Object OwnershipBucket owner enforced (ACLs disabled); use policies only
IAM policiesLeast privilege: specific actions on specific bucket ARNs and prefixes
Bucket policiesDeny non-TLS requests, deny uploads without the required encryption, restrict to VPC endpoints
EncryptionSSE-S3 is the default; use SSE-KMS with customer-managed keys for regulated data, plus S3 Bucket Keys to cut KMS costs
VPC gateway endpointKeep S3 traffic from private subnets off the internet (and free of NAT charges)
Access PointsSeparate named entry points with their own policies for different consumers of a shared bucket
Lake FormationTable- and column-level permissions for analytics engines instead of raw bucket access
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyInsecureTransport",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": ["arn:aws:s3:::acme-lake-prod", "arn:aws:s3:::acme-lake-prod/*"],
      "Condition": { "Bool": { "aws:SecureTransport": "false" } }
    },
    {
      "Sid": "DenyWrongKmsKey",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::acme-lake-prod/*",
      "Condition": {
        "StringNotEqualsIfExists": {
          "s3:x-amz-server-side-encryption-aws-kms-key-id": "arn:aws:kms:ap-south-1:111122223333:key/1111-2222"
        }
      }
    }
  ]
}
{
  "Version": "2012-10-17",
  "Statement": [
    { "Sid": "ListSilverOnly", "Effect": "Allow", "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::acme-lake-prod",
      "Condition": { "StringLike": { "s3:prefix": ["silver/*"] } } },
    { "Sid": "ReadWriteSilver", "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": "arn:aws:s3:::acme-lake-prod/silver/*" }
  ]
}

The second policy is an IAM (identity) policy for a Glue job role: it can list and change only the silver prefix. Note that ListBucket applies to the bucket ARN, while object actions apply to bucket/* ARNs: a common source of AccessDenied errors.

7. Versioning, Object Lock & Replication

8. Event Notifications

S3 can announce new or deleted objects to Lambda, SQS, SNS, or EventBridge (which allows richer filtering and many targets). This is how file-arrival pipelines start.

# send all events to EventBridge, then route with rules
aws s3api put-bucket-notification-configuration --bucket acme-lake-prod \
  --notification-configuration '{"EventBridgeConfiguration": {}}'

# EventBridge rule pattern: new .csv files under raw/partner/
{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
    "bucket": { "name": ["acme-lake-prod"] },
    "object": { "key": [{ "wildcard": "raw/partner/*.csv" }] }
  }
}

9. Performance & Cost

TopicGuidance
Request ratesAt least 3,500 PUT/COPY/POST/DELETE and 5,500 GET/HEAD per second per prefix; spread hot workloads across prefixes
Large objectsMultipart upload (parallel parts) and byte-range GETs (parallel reads)
Small filesCompact into larger files; each file is a separate request and a separate task for Spark/Athena
Long distanceS3 Transfer Acceleration or Direct Connect for uploads from far away or on-premises
File system accessMountpoint for Amazon S3 mounts a bucket for read-heavy workloads that expect files
Cost driversStorage GB-month, requests (many small files are expensive), data transfer out and between regions, retrievals from IA/Glacier, KMS requests
VisibilityS3 Storage Lens and S3 Inventory reports show growth, small files, incomplete uploads and access patterns

S3 Tables offer table buckets with fully managed Apache Iceberg tables (automatic compaction and snapshot management); see the Apache Iceberg guide.

10. Common Interview Questions

QuestionShort answer
Is S3 a file system?No. It is a flat key-value object store; "folders" are key prefixes. Renames are copy + delete, which is why table formats avoid relying on renames
What consistency does S3 offer?Strong read-after-write consistency for all PUTs, DELETEs and LISTs
How do you design an S3 data lake?Zones (raw, bronze, silver, gold) in separate buckets or prefixes; columnar compressed files of 128 MB–1 GB; Hive-style partitions on filter columns; encryption, lifecycle, Glue Catalog and Lake Formation
How do you reduce S3 costs?Lifecycle to IA/Glacier, Intelligent-Tiering, expire noncurrent versions, abort incomplete uploads, compact small files, VPC endpoints to avoid NAT charges
How do you secure a bucket for PII?Block Public Access, SSE-KMS with a customer key and Bucket Keys, deny non-TLS and unencrypted writes, least-privilege roles, VPC endpoint restrictions, Macie scanning, CloudTrail data events
How do you trigger processing when a file lands?S3 event notification (or EventBridge) to Lambda/SQS/Step Functions, with idempotent processing because events can repeat
Governance vs compliance mode in Object Lock?Governance can be overridden by users with special permission; compliance cannot be shortened or removed by anyone until retention ends