All questions
#10Social & FeedsMedium

Design Instagram

Upload, store and serve photos to a feed, with likes and follows.

Meta logo
Google logo
Amazon logo
Snapchat logo

Asked at Meta, Google and 2 more

3 min read·7 sections

Instagram lets people upload photos and videos, follow others, and scroll a feed of what they post. The design combines three things: a media pipeline for uploads, object storage plus a CDN for serving images, and a feed built from the follow graph.

Requirements#

Functional

  • Upload a photo with a caption.
  • Follow and unfollow users.
  • View a feed of posts from followed accounts, and any user's profile grid.
  • Like and comment on posts.

Non-functional

  • Images load fast worldwide; the feed renders in under a second.
  • Uploaded media is never lost.
  • 500 million daily users; reads far outnumber uploads.

Estimates#

MetricEstimate
Uploads100M photos/day ≈ 1,200/s
Stored per photo~2 MB original + ~500 KB of resized versions
New storage per day100M × 2.5 MB ≈ 250 TB
Feed and image readsBillions per day, mostly served by the CDN

Upload flow#

Sending large files through API servers wastes their bandwidth. Instead, clients upload straight to object storage with a pre-signed URL:

App
Upload APIissue pre-signed URL
App
Object storageoriginal photo
Media events
Image workersresize + strip EXIF
Image workers
Object storage
Image workers
Post service
Posts DB
Media goes straight to object storage; workers make resized copies for every screen size
  1. The app asks the upload API for a pre-signed URL and uploads the photo directly.
  2. Storage emits an event; workers create thumbnail, feed and full-size versions in modern formats like WebP or AVIF.
  3. The post is published only once its versions exist.

Serving images#

All media is served through a CDN. URLs include the size and a content hash, such as /p/9f2c.../640.webp, so they can be cached forever. Clients request the size that matches the screen.

Data model#

sql
users   (id, username, bio, avatar_url, created_at)
posts   (id, user_id, caption, media_key, created_at)
follows (follower_id, followee_id, created_at)   -- PK (follower_id, followee_id)
likes   (post_id, user_id, created_at)           -- PK (post_id, user_id)
  • Posts are sharded by user_id, so a profile grid is one shard query sorted by time.
  • Follows are stored twice, indexed by follower and by followee, to answer both "who do I follow" and "who follows me".
  • Like counts are kept as a counter on the post (updated asynchronously) instead of COUNT(*) on every view.

The feed#

Like any social feed, use fan-out on write for most accounts (push post IDs into followers' feed caches) and fan-out on read for celebrities, merged at read time. See the News Feed design for the full trade-off.

Scaling and reliability#

  • Durability: object storage replicates across zones; keep originals in a cheaper storage class after 30 days.
  • Counters: likes on viral posts can mean thousands of writes per second to one row. Buffer increments in Redis and flush them periodically.
  • Read replicas: profile and post metadata are read-heavy and tolerate small delays.
  • Search and explore: a separate pipeline indexes posts and hashtags into a search cluster.

Finished this walkthrough?

Mark it as read to track your progress in the list.