Photo-sharing combines media handling (heavy I/O), social graph (consistency challenges), and feed serving (scale challenges). Here’s how to design it.

Functional requirements

  • Upload photos / videos.
  • Follow / unfollow.
  • See home timeline (feed of follows’ posts).
  • See profile timeline.
  • Like, comment, save.
  • Search.

Non-functional

  • Read-heavy (~100:1).
  • Sub-second feed render.
  • Eventual consistency OK on follow propagation.
  • Petabytes of media at scale.

Architecture

Client
   direct upload (signed URL)
S3 (raw)
   event
Image processor (variants: thumbnail, 720p, 1080p, 4K)
  
S3 (processed) + DB row
  
CDN (CloudFront / Cloudflare)
   serve
Client

Plus the social side:

Post → Kafka → fanout workers → user feed entries (Redis sorted sets)

Upload pipeline

  1. Client requests signed S3 upload URL from API.
  2. Client uploads directly to S3 (bypasses your servers; saves bandwidth).
  3. S3 emits ObjectCreated event to SNS / EventBridge.
  4. Image-processor worker picks up event:
    • Decode (PIL / Sharp / native).
    • Generate variants (thumbnails, sizes, formats).
    • Upload variants to S3.
    • Insert DB row with metadata.
  5. Mark post as ready; enqueue fanout to feeds.

Image processing

  • Sizes: 150×150 (thumb), 480w, 720w, 1080w, 1920w. Crop to common aspect ratios.
  • Formats: WebP (modern), AVIF (smaller), JPEG (fallback).
  • HEIC input: from iOS; convert at processing time.
  • EXIF: strip for privacy unless explicitly preserved.

Run on K8s with autoscaling, or use serverless (Lambda + Sharp). For massive volume, GPU-accelerated processing pays off.

Feed (timeline)

Hybrid fanout (same as Design Twitter ):

  • Normal users: fanout-on-write to followers’ Redis sorted sets.
  • Celebrities (>1M followers): fanout-on-read.
  • Feed = merge precomputed timeline + recent posts from celebs followed.
Read home timeline:
  base = Redis ZREVRANGE timeline:{user_id} (precomputed)
  celeb_recent = for each celeb followed: their last 50 posts
  merged = merge_by_time(base + celeb_recent)
  paginate cursor-style

Follows

CREATE TABLE follows (
    follower_id BIGINT,
    followee_id BIGINT,
    created_at TIMESTAMPTZ,
    PRIMARY KEY (follower_id, followee_id)
);
CREATE INDEX follows_followee ON follows (followee_id, follower_id);

For celebrities with 100M followers, this table partitioned by follower_id hash.

When user A follows user B:

  • Insert row.
  • For B’s recent posts (last 50), inject into A’s timeline (cheap backfill).
  • For new B posts going forward, A is in the fanout list.

When unfollow: similar in reverse, lazy clean.

Likes / comments

  • Likes: counter in Redis (write-behind to durable). Per-post likes Redis hash; per-user liked_posts set.
  • Comments: append-only, per-post in DB. Cassandra-style at scale.
  • Hashtags: indexed in Postgres FTS or Elasticsearch.
  • Users: indexed by username.
  • Discovery: ML-driven recs from engagement features.

See Design a Search System .

Storage and CDN

Images: ~1 MB each at high quality. 100M uploads/day = 100 TB/day. Tier:

  • Hot (last 30 days): S3 Standard.
  • Warm (30–365 days): S3 IA.
  • Cold: S3 Glacier.

CDN at the edge serves 95%+ of bytes. Origin only on cache miss.

Capacity arithmetic

  • 200M DAU × 5 photos viewed = 1B views/day.
  • At 500 KB avg per view from CDN: 500 TB/day egress.
  • Mostly served from cache; origin pulls maybe 1–5 TB/day.

The CDN cost dominates everything.

Common interview probes

  • Hot post (10M likes/hour)? Counter shards across Redis nodes; aggregate periodically.
  • Delete a post? Soft-delete in DB; CDN cache TTL handles staleness; eventual hard-delete cleans S3.
  • Inappropriate content? ML moderation pipeline before publish; user reporting; manual review queue.
  • Multi-region? Per-region storage + CDN; eventual replication of metadata.

Read this next

If you want a small “Insta-clone” reference (uploads + feeds), it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .