Skip to main content

Design Instagram (Photo Sharing)

Level 10: Level 10: Applied Case Studieshard40 mininstagramblob-storagecdn

Metadata DB plus object storage plus CDN, upload direct to S3 with presigned URLs, generate resolution variants async, reuse hybrid fan-out for the feed, shard viral like counters, and never store image bytes in the database.

A fan-out timeline bolted onto a media pipeline

Instagram is a fan-out timeline (you already know that half from the news-feed lesson) bolted onto a media pipeline. The new material is how you store and serve photos and videos.

Split blob from metadata

The single most important decision: photos go in object storage (S3, GCS), and the database stores only metadata plus a pointer (the object key or URL). A post row is (post_id, user_id, caption, media_key, created_at, like_count), a few hundred bytes. The 3MB photo never enters the database. Storing image bytes in Postgres or MySQL bloats the row store, wrecks buffer-cache hit rates, makes backups enormous, and cannot be served from a CDN. The metadata DB (users, posts, follows) can be a partitioned relational store or a KV store; the media store is separate and optimized for large immutable blobs.

Presigned uploads

The naive path streams the photo through your app servers to S3, which doubles bandwidth and makes your app tier a throughput bottleneck. Instead the client asks the app server for a presigned S3 URL, then uploads the bytes directly to S3. Your app servers never touch the image bytes. The app tier does auth and issues a short-lived signed URL; S3 absorbs the upload.

Client -> app: "I want to upload" -> app returns presigned PUT URL (+ media_key)
Client -> S3: PUT bytes directly (app never sees them)
S3 event -> queue -> transcode worker: make 1080/640/thumbnail variants
Worker -> writes variant keys; marks post ready; triggers feed fan-out

Async variants, CDN, feed reuse, counters

On upload you generate multiple resolutions and a thumbnail (1080w, 640w, 320w, a small square thumb) via a worker triggered by an S3 event through a queue. This is async so the user is not blocked. Clients request the resolution that fits their screen, saving bandwidth.

Media is immutable and read far more than written, the perfect CDN workload. Serve every image and thumbnail through a CDN (CloudFront, Fastly) so 90%+ of reads hit an edge cache near the user and never touch origin. Because media is immutable you set long TTLs and use a versioned key if you ever replace it.

The timeline is the same hybrid fan-out: push post ids to normal followers' timelines, pull for celebrity accounts, store ids not bodies, hydrate metadata in a batch, and resolve media keys to CDN links at render time.

Likes and comment counts on a viral post get millions of increments. A single UPDATE ... SET like_count = like_count + 1 row is a hot-row contention nightmare. Shard the counter across N sub-counters and sum them, or maintain an approximate count in Redis flushed periodically. Exact like counts are not worth serializing every write.

Interview nuance: estimate to show you can size it. 100M photos/day at 2MB average is 200TB/day of new media before replication, and with 3x replication or erasure coding that is the storage bill the CDN then fronts. Read bandwidth dwarfs write bandwidth, which is the whole reason a CDN is non-negotiable.

Recap: metadata DB plus object storage plus CDN, upload direct to S3 with presigned URLs, generate resolution variants async, reuse hybrid fan-out for the feed, and never store image bytes in the database.

Apply

Your turn

The task this lesson builds to.

Design upload-to-view for a photo-sharing app including media storage, metadata, and feed delivery to a global audience.

Think about

  1. How do you split blob storage from metadata?
  2. How do presigned uploads and a CDN serve media efficiently?
  3. How does the feed reuse fan-out patterns?

Practice

Make it stick

A second problem on the same idea, so it survives past today.

Design Instagram Stories: media that 500M daily users post and view but that expires and is deleted after 24 hours. Explain how the ephemeral lifecycle changes storage, delivery, and the feed compared to permanent posts.

Think about

  1. How does a storage TTL/lifecycle policy replace a massive delete job?
  2. Why does fan-out-on-read fit Stories where fan-out-on-write fits permanent posts?
  3. How do CDN TTLs interact with the 24-hour expiry?