Design Instagram
Photo upload, feed, likes, comments, stories, and object storage at 2B+ users with global CDN delivery.
Interview tip Photos → S3 + CDN thumbnails (multiple sizes). Metadata in Cassandra. Feed uses same hybrid fan-out as news feed. Separate hot path for image bytes vs metadata.
① Functional requirements
- Upload photo with optional filter applied client-side or server-side
- Generate thumbnails: 150px, 320px, 640px, 1080px
- Home feed: photos from followed users, ranked
- Like and unlike photos; display like count
- Comment on photos (flat comments, paginated)
- User profile: grid of user's photos
- Follow/unfollow users
Out of scope (state in interview)
- Stories (24h ephemeral)
- Reels / video (brief mention)
- Direct messaging
- Explore/discovery algorithm
② Non-functional requirements
- Photo upload complete < 5s on 4G
- Feed load < 2s; images load progressively
- 99.9% availability on image CDN
- 100M photos/day (~1.2K uploads/sec)
- Global low-latency image delivery
③ Back-of-the-envelope scale
Assumptions
- 100M photos/day → ~1.2K uploads/sec avg, ~5K/sec peak
- Avg 2MB raw → 200KB JPEG after compression; 4 thumbnail sizes ≈ 400KB total per photo
- Storage: 100M × 400KB × 365 ≈ 14.6 PB/year (CDN + S3)
- Feed reads: 2B MAU × 3 sessions × 2 feed loads = 12B/day → ~140K/sec
- Likes: 10 likes/photo avg → 1B likes/day → ~12K writes/sec
- Avg 300 followers → fan-out: 1.2K × 300 = 360K feed writes/sec
Store photo IDs in feed cache (not URLs). CDN URLs derived from photo_id + size template. Image processing async — show placeholder until thumbnails ready. Hybrid fan-out for users with > 100K followers.
④ High-level architecture
Instagram Photo Platform
Mobile Clients
API Gateway
Media Service (upload)
Photo Service (metadata)
Feed Service
Social Graph
Image Processing Workers
Fan-out Workers
S3 + CDN
Cassandra (photos, feeds)
Redis (feed cache)
Upload photo→S3 raw→Resize + CDN→Fan-out feed
Upload flow: presigned S3 URL → client uploads → webhook triggers image workers → multiple sizes to CDN → photo metadata written → fan-out to follower feeds. Client polls or push notification when processing complete.
⑤ Data flow & execution path
End-to-end execution flow
① Client→② API / LB→③ Core services→④ Cache + DB→⑤ Message queue→⑥ Async workers
Sync path: validate → authorize → read/write primary store
Async path: publish domain events → consumers (email, analytics, search index)
Read-heavy path: CDN / edge cache → regional cache → DB replica
Failure path: retry with backoff, DLQ, idempotent handlers
In interviews, trace one user action through this diagram. State what is synchronous (user waits) vs asynchronous (background), and where you enforce idempotency.
⑥ API & interfaces
| Endpoint / flow | Purpose | Notes |
|---|---|---|
| POST /v1/photos/upload-url | Get presigned URL | Returns {uploadUrl, photoId, expiresAt} |
| POST /v1/photos/{id}/complete | Finalize upload | Triggers processing; returns status processing|ready |
| GET /v1/feed?cursor= | Home feed | Photo cards with CDN URLs for thumbnails |
| POST /v1/photos/{id}/like | Like photo | Idempotent; async counter increment |
| GET /v1/photos/{id}/comments?cursor= | Comments | Paginated; newest first |
| POST /v1/photos/{id}/comments | Add comment | Returns commentId; notifies photo owner |
⑦ Data model & storage
photos:
likes:
comments:
photo_id, user_id, caption, filter, cdn_paths {150,320,640,1080}, like_count, created_atlikes:
photo_id, user_id (composite PK for idempotency)comments:
comment_id, photo_id, user_id, text, created_at| Store | What | Why |
|---|---|---|
| S3 + CloudFront CDN | Image blobs (all sizes) | Immutable; cache 1 year; geo-distributed |
| Cassandra | Photos, comments, likes | Partition by photo_id; high write throughput |
| Redis Sorted Sets | User feed cache | Photo IDs ranked by score; hybrid fan-out |
| Kafka | Processing + fan-out queue | Decouple upload from feed update |
⑧ Deep dive — core components
Image processing pipeline
On upload complete: worker downloads raw from S3, applies filter (if server-side), generates 4 JPEG sizes with ImageMagick/libvips, uploads each to CDN path
/photos/{photo_id}/{size}.jpg. Update photo record status=ready. Typical processing: 2–5 seconds.Client shows blurred placeholder (LQIP — low-quality image placeholder, 20×20 base64) until ready. Webhook or polling on
GET /photos/{id}/status.Feed with photo metadata hydration
Feed cache stores photo_ids in ranked order. On feed read: batch MGET photo metadata from Cassandra (or local cache). Construct CDN URLs from template — no URL stored per feed entry. Progressive loading: 150px in feed list, 640px on tap.
Like count consistency
Like write: INSERT into likes table (idempotent PK). Async: Redis INCR photo:{id}:likes. Display count from Redis (stale OK by seconds). Periodic reconciliation job syncs Redis → Cassandra like_count. Unlike: DELETE from likes + DECR.
Storage cost optimization
CDN caches hot images at edge — S3 egress minimal. Lifecycle: move originals to Glacier after 90 days if only thumbnails needed. WebP format saves 30% vs JPEG for supported clients. Deduplicate identical uploads via perceptual hash (optional).
⑨ Trade-offs & alternatives
| Decision | Option A | Option B | Pick when |
|---|---|---|---|
| Filter | Client-side | Server-side | Client saves server CPU; server for consistency |
| Feed fan-out | Push (write) | Pull (read) | Push for normal; pull for celebrities |
| Like count | Eventually consistent | Strongly consistent | Eventual standard for social; strong overkill |
| Image format | JPEG | WebP/AVIF | JPEG universal; WebP for bandwidth savings |
| Comment model | Flat list | Threaded tree | Flat simpler; threaded for Twitter-style |
⑩ 45-minute interview script
- 0–5 min: Clarify upload, feed, likes, comments, followers
- 5–12 min: Scale — photos/day, storage PB, fan-out math
- 12–22 min: Architecture — media, photo, feed, graph services
- 22–30 min: Image processing pipeline and CDN strategy
- 30–36 min: Hybrid feed fan-out (reuse news feed pattern)
- 36–42 min: Like count async increment
- 42–45 min: Storage cost and multi-resolution thumbnails
⑪ Likely follow-up questions
| Question | Short answer |
|---|---|
| Photo upload on slow 3G? | Client-side resize before upload; chunked upload; retry with exponential backoff |
| Celebrity with 50M followers posts? | Skip fan-out; pull at read time; merge with precomputed feed |
| Delete photo? | Mark deleted in DB; CDN cache expires via TTL; purge from feeds async |
| Duplicate photo detection? | Perceptual hash on upload; flag or block duplicates |
| Comments on viral photo (1M comments)? | Paginate; cache top comments; rate limit comment writes |
| Multi-region users? | S3 cross-region replication; CDN global; Cassandra multi-DC |
⑫ Revision checklist
- Presigned S3 upload flow
- Multiple thumbnail sizes (150–1080px)
- Async image processing workers
- CDN for all image delivery
- Feed stores photo IDs not blobs
- Hybrid fan-out for celebrity users
- Like idempotency via composite PK
- Eventually consistent like counts
- 100M photos/day scale math
- Progressive image loading strategy