Engineering Atlas › System Design Interviews

Amazon S3 for system design interviews

13 min read · last reviewed 2026-10-17

Open in the interactive app: practice, quiz, mock interview →

In one minute

How it works

Buckets, keys and objects

A bucket is a namespace in one region. A key is any UTF-8 string up to 1,024 bytes; photos/2026/a.jpg is one flat key, and "folders" are a listing convenience using a delimiter. An object is immutable once written: a PUT to an existing key replaces it atomically, and with versioning enabled the old version is kept. Objects can be up to 50 TB (raised from 5 TB in December 2025; AWS), but a single PUT is limited to 5 GB.

Multipart upload

Large objects are uploaded in parts. CreateMultipartUpload returns an UploadId. The client uploads parts numbered 1 to 10,000, each 5 MiB to 5 GiB except the last, in any order and in parallel, and each UploadPart returns that part's ETag (AWS limits). Because the part count is capped, part size caps object size: 16 MiB parts top out near 156 GiB, and only parts close to 5 GiB reach the 48.8 TiB maximum, so pick the part size from the largest file you expect. CompleteMultipartUpload sends the list of part numbers and ETags in ascending order, and S3 stitches them into one object atomically. Until completion or AbortMultipartUpload, the parts are stored and billed but invisible, which is why every bucket should have a lifecycle rule that aborts incomplete uploads.

Reading, listing and conditional writes

GET accepts a Range header, so clients download large objects as parallel byte ranges. ListObjectsV2 returns up to 1,000 keys per page in lexicographic order. Conditional writes (If-None-Match: * to create only if absent, If-Match: <etag> to replace only an expected version) let S3 act as a simple coordination point, for example for table-format commit files. When several conditional writers race, the first to finish wins and the rest get 412 Precondition Failed; a concurrent delete can produce 409 Conflict, and for multipart uploads that means starting the upload again (AWS docs).

Storage classes and lifecycle

The same API fronts cost tiers from Standard through Infrequent Access to Glacier archive classes. Lifecycle rules move or expire objects by age or prefix; colder tiers trade cheaper storage for retrieval fees and, for archives, hours of restore time.

Down the stack

Layer 1The contract

After a successful PUT or CompleteMultipartUpload returns, any subsequent GET, HEAD or LIST in any client sees the new object; overwrites and deletes are likewise immediately visible. Concurrent writers to one key get last-writer-wins unless they use conditional writes, and there is no multi-object transaction. Durability is designed for 99.999999999 percent per object per year, and Standard is designed for 99.99 percent availability (AWS docs), while the SLA only pays service credits below 99.9 percent (AWS SLA). An acknowledged write is already stored redundantly across zones. Typical first-byte latency is tens of milliseconds for small objects, and AWS's own performance guide tells latency-sensitive applications to expect roughly 100 to 200 ms (AWS docs). A single connection sustains on the order of 50 to 100 MB/s (hedge: varies with object size and client), so aggregate throughput comes from many connections.

Layer 2The mechanism

AWS has described S3 as hundreds of microservices; the public picture has three main layers.

Front end. DNS spreads clients over many front-end hosts, which terminate TLS, verify SigV4 signatures, evaluate IAM and bucket policies, and call the index and storage layers.

Index (metadata). A replicated key-value system maps bucket and key to size, ETag, checksum, version, storage class and shard locations. It is partitioned by key range, hence the per-prefix rates of at least 3,500 writes and 5,500 reads per second and automatic, gradual splitting of hot ranges, with 503 Slow Down errors meanwhile. Strong consistency was added while keeping the metadata cache: new replication logic orders operations per object, and a "witness" component notified on every object change lets a read check whether its cached entry is stale and, if so, go to the persistence tier (Werner Vogels). The internals beyond that are not public.

Storage. Object bytes are split into chunks and erasure coded with Reed-Solomon codes: a chunk becomes k data shards plus m parity shards placed on different drives, hosts and availability zones, and any k of them reconstruct the data (Warfield). A scheme in the spirit of 5 data plus 4 parity (hedge: the actual parameters are not published and vary) survives losing a whole zone plus more drives, at under 2x storage overhead instead of 3x for replication. Storage hosts run ShardStore, a Rust key-value store AWS checked with lightweight formal methods, which caught 16 issues before they reached production (SOSP 2021), and auditors continuously verify checksums and rebuild bad shards from parity.

Integrity. Each part's ETag is typically the MD5 of its bytes for unencrypted or SSE-S3 objects. A multipart object's ETag is the MD5 of the concatenated binary part MD5s, followed by - and the part count, so it is not the MD5 of the whole object. For end-to-end integrity, all AWS-owned clients (SDKs and CLI) now compute a checksum on every upload, CRC64NVME unless you pick another (CRC32, CRC32C, SHA-1, SHA-256 and newer XXHash and SHA-512 options), and S3 recomputes it and rejects a mismatch before storing (AWS docs). SDKs do not compute MD5 automatically.

Layer 3The machine

Most S3 bytes sit on hard drives. A modern HDD holds 20 TB or more but still delivers only about 120 random IOPS, a figure that has barely moved since 2006, and roughly 200 to 250 MB/s sequential, so IOPS per TB keeps falling as drives grow. S3's answer is to spread every customer's data thinly across a huge fleet, so a workload's hot spots land on thousands of drives that also hold colder data, and aggregate demand smooths out statistically. Erasure coding helps reads too: a GET can start from whichever k shards respond fastest, hiding a slow drive.

Each request is an HTTPS exchange, so connection reuse matters; the AWS CRT-based clients issue 8 to 16 MB ranged GETs or parts over many connections to saturate 10 to 100 Gbit/s NICs. Per-request cost is fixed (roughly $0.005 per 1,000 PUTs and $0.0004 per 1,000 GETs for Standard in us-east-1; hedge: check current pricing), so millions of tiny objects cost more in requests than in storage, which runs about $0.023 per GB-month.

Why it's built this way

  1. Exabytes cheaply means hard drives, which are slow at random I/O, so data is spread over huge numbers of drives and throughput comes from parallelism.
  2. Triple replication across zones would triple cost, so S3 erasure codes, paying CPU and network on repair for under 2x overhead.
  3. A range-partitioned flat key space scales indefinitely, but each range has finite capacity, hence per-prefix limits and splitting.
  4. Immutable objects keep replication, caching and erasure coding simple, so there are no in-place writes and large uploads commit parts atomically.
  5. Customers assumed read-after-write, so S3 made the metadata layer strongly consistent instead of leaving clients to work around stale reads.

Diagram

sequenceDiagram
    participant C as Client
    participant F as Front end
    participant I as Index (metadata)
    participant S as Storage nodes (EC shards)
    C->>F: CreateMultipartUpload
    F-->>C: UploadId
    par parts in parallel
        C->>F: UploadPart 1 (16 MB)
        F->>S: write k+m shards across AZs
        F-->>C: ETag 1
    and
        C->>F: UploadPart 2 (16 MB)
        F->>S: write k+m shards across AZs
        F-->>C: ETag 2
    end
    C->>F: Complete [(1,ETag1),(2,ETag2)]
    F->>I: commit object manifest atomically
    F-->>C: ETag "md5(md5s)-2"

Worked example

A video service ingests 50,000 uploads a day, averaging 1.2 GB, and serves 30 million plays a day of transcoded renditions through a CDN.

Ingest is 60 TB a day. Clients upload directly to S3 with presigned multipart URLs, so bytes never touch application servers. With 16 MB parts a 1.2 GB file is 75 parts; the upload bandwidth is the same, but a dropped part is retried alone instead of restarting the file. A lifecycle rule aborts incomplete uploads after 3 days.

Keys are raw/<upload_id>/source.mp4 and renditions/<video_id>/<height>/<segment>.ts; random IDs spread writes across the key space. With 2-second segments, a 10-minute video in 5 renditions is 1,500 objects, so 75 million PUTs a day, about $375 a day in requests alone. Packing segments into one fMP4 file per rendition with byte-range reads cuts PUTs 300-fold.

After a year storage is about 22 PB of originals plus renditions. Originals move to Glacier Flexible Retrieval after 30 days, cutting their cost by roughly 80 percent. The CDN absorbs most reads, so S3 sees only a few thousand GETs per second of cache misses.

In the wild

Trade-offs

OptionStrengthsWeaknessesChoose when
S3 StandardDurable, unlimited, cheap per GB, strong consistency10 to 100 ms latency, per-request costsBlobs, data lakes, backups, static assets
S3 Express One ZoneSingle-digit ms, very high request ratesOne zone, higher price per GBHot intermediate data for analytics or ML
EBS or local NVMeSub-ms block I/O, in-place writesOne instance, you manage durabilityDatabases and file systems
EFS or FSxPOSIX files shared across hostsHigher cost, throughput tied to configLegacy apps needing a file system
DynamoDBSingle-digit ms key-value with conditions400 KB item limit, costly for bulk bytesMetadata about objects

Pitfalls in production

Leadership lens

Check yourself

  1. Why is the ETag of a multipart object not the MD5 of the whole file?

    Show answer

    S3 computes it from the parts as the MD5 of the concatenated part digests plus a part count, so it never has to rehash the assembled object.

  2. A team writes all objects under logs/2026-10-15/ and sees 503 SlowDown at 6,000 writes per second. What is happening?

    Show answer

    All writes hit one key range above its per-prefix rate; S3 will split the range over time, but spreading keys (such as hashed prefixes) avoids the hot spot.

  3. Why does erasure coding allow both lower cost and higher durability than three replicas?

    Show answer

    k data plus m parity shards survive any m losses at (k+m)/k overhead, 1.8x for 5+4, versus 3x for replicas that survive two.

  4. Can two clients safely use S3 to elect a leader?

    Show answer

    Yes: each PUTs the same key with If-None-Match: * and only one succeeds, though lease expiry still needs care.

Sources and further study

Primary

Systems docs

Books

Other curricula

Watch

Free resources

Open in the interactive app: practice, quiz, mock interview →