Overview
Instagram is a photo and video sharing app with a follow graph and a personalized home feed. The core design challenges are storing and serving huge volumes of media cheaply and quickly, and building each user's feed from the accounts they follow in milliseconds, even when some accounts have hundreds of millions of followers.
The system is heavily read-dominated: a post is written once and viewed many times. Media bytes go to object storage behind a CDN, while metadata (users, posts, follows, likes) lives in sharded databases and caches. Feeds are usually built with a hybrid approach: precompute feeds for most users at post time (fan-out on write) and merge in posts from celebrity accounts at read time (fan-out on read).
For most writers, the printer adds each new article to their subscribers' editions as soon as it is written. For a handful of superstar writers read by millions, updating every edition is too slow, so their articles are slotted in when a reader picks up their copy. The photos themselves are stored in a warehouse and shipped from local depots near every city.
Requirements
- Functional: upload photos and videos with captions; follow users; view a home feed; like and comment; view profiles.
- Non-functional: feed loads under 200 ms at P99; media available worldwide; high availability; eventual consistency is acceptable for likes and feeds.
- Scale assumption: 500M daily active users, 100M new posts per day, each user opens the feed about 10 times a day.
- Out of scope: direct messages, stories ranking details, ads, and search.
Where it shows up in interviews
Recognize it when: users see content from people they follow.
- Design Twitter / X
- Design News Feed
Recognize it when: large uploads served globally.
- Design YouTube
- Design Dropbox / Google Drive
Where it is used in real software
Large photo platforms store originals and resized variants in object storage and serve them from edge caches.
Instagram's early engineering posts describe sharding PostgreSQL by user and generating time-sortable IDs inside the database.
Modern feeds rank candidate posts with machine learning rather than showing strict reverse-chronological order.
Key terms
- Fan-out on write
- When a user posts, push the post ID into each follower's precomputed feed.
- Fan-out on read
- Build the feed at request time by pulling recent posts from followed accounts.
- Celebrity problem
- Accounts with huge follower counts make fan-out on write too expensive.
- Pre-signed URL
- A time-limited URL that lets clients upload directly to object storage.
- Time-sortable ID
- An ID whose high bits are a timestamp, so sorting by ID sorts by time.
How it works, step by step
- 1Upload media directly to storage
The client asks the API for a pre-signed URL and uploads the file straight to object storage, keeping large bytes off app servers.
- 2Process asynchronously
A queue triggers workers that create thumbnails and multiple resolutions, strip metadata, and scan content.
- 3Save post metadata
Write the post (ID, author, caption, media keys) to a database sharded by user ID.
- 4Fan out
For normal accounts, push the post ID into followers' feed lists in a cache such as Redis. Skip accounts above a follower threshold.
- 5Read the feed
Fetch the precomputed list, merge recent posts from followed celebrities, rank, hydrate post details from cache, and return media CDN URLs.
STEP 1The client uploads the photo directly to object storage using a pre-signed URL.
Back-of-the-envelope estimates
500M DAU, 100M posts per day, average stored media 2 MB per post across all sizes.
| Quantity | Calculation | Result |
|---|---|---|
| Upload rate | 100M / 86400 | about 1.2K posts per second |
| Feed reads | 500M x 10 / 86400 | about 58K per second (peaks 3x) |
| New media per day | 100M x 2 MB | about 200 TB |
| Fan-out writes | 1.2K posts/s x 200 average followers | about 240K feed inserts per second |
NOWQuantity: Upload rate | Calculation: 100M / 86400 | Result: about 1.2K posts per second
Reads dominate, so caching feeds and serving media from a CDN are essential. Fan-out writes are large but spread across many cache shards.
Implementation
const CELEBRITY_THRESHOLD = 100_000; // Called by a queue consumer after a post is saved.async function fanOut(post: { id: string; authorId: string; createdAt: number }) { const author = await users.get(post.authorId); if (author.followerCount > CELEBRITY_THRESHOLD) return; // merged at read time instead for await (const batch of follows.followersOf(post.authorId, { batchSize: 1000 })) { const pipeline = redis.pipeline(); for (const followerId of batch) { pipeline.zadd(`feed:${followerId}`, post.createdAt, post.id); pipeline.zremrangebyrank(`feed:${followerId}`, 0, -801); // keep the newest 800 } await pipeline.exec(); }} async function readFeed(userId: string, limit = 20) { const pushed = await redis.zrevrange(`feed:${userId}`, 0, 200); const celebs = await follows.celebritiesFollowedBy(userId); const pulled = (await Promise.all(celebs.map((c) => posts.recentIds(c, 20)))).flat(); const candidates = [...new Set([...pushed, ...pulled])]; const ranked = await ranker.score(userId, candidates); return posts.hydrate(ranked.slice(0, limit)); // captions, like counts, CDN URLs}Complexity and performance
Cheap reads, expensive for large accounts.
Cheap writes, slow reads.
Usually a small number.
Trade-offs
Push gives instant reads but costs storage and write amplification. Pull saves writes but makes reads slow. The hybrid uses push for normal accounts and pull for celebrities.
Likes and feed contents can be seconds stale. Use counters aggregated asynchronously instead of locking rows on every like.
Variants and related techniques
Ranking needs a candidate generation step plus an ML scoring service.
Adds transcoding into adaptive bitrate formats and chunked delivery.
Common mistakes
- Uploading media through application servers.
Fix: Use pre-signed URLs to upload directly to object storage.
- Pure fan-out on write.
Fix: Treat high-follower accounts separately and merge their posts at read time.
- Updating like counts synchronously in the post row.
Fix: Use sharded or buffered counters and update asynchronously.
Interview questions
How do you handle a celebrity with 300 million followers posting?
Do not fan out their posts. Mark them as celebrities, store their posts once, and when a follower loads the feed, pull recent posts from the celebrities they follow and merge them with the precomputed feed before ranking.
How do you serve images fast worldwide?
Store originals and resized variants in object storage, serve them through a CDN with long cache lifetimes and content-hashed keys, and have the client request the size that fits the screen.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| Estimate storage and bandwidth for one year of uploads | Easy | Capacity planning. |
| Design the hybrid feed with ranking and pagination | Hard | Fan-out strategy. |