Design Instagram
You're asked to design Instagram, usually scoped to posting and the home feed. A user should be able to upload a photo, and everyone who follows them should see it in a personalized feed of recent posts that loads in under a second, assembled from a pool of billions of posts.
Two things make this hard. Building each feed from scratch at read time doesn't scale to hundreds of millions of daily users, and building it ahead of time breaks the moment an account with 400 million followers posts. Most of this interview is spent resolving that tension.
Clarifying the requirements
- Which surfaces are in scope? Instagram is posting, the home feed, search and explore, stories, direct messages, and reels. Nobody designs all of it. Propose posting plus the home feed and let the interviewer redirect.
- Chronological or ranked? A reverse-chronological feed is a merge problem. A ranked feed adds a scoring layer and changes what you precompute.
- How fresh does the feed need to be? Seconds, or is a minute acceptable? This is the freshness budget that licenses everything downstream.
- What's the follower distribution? Ask this explicitly. The answer, a long tail of normal users plus a handful of accounts with hundreds of millions of followers, is what forces the hybrid design later.
Assume: posting and a reverse-chronological home feed, freshness within seconds, media in scope.
Back-of-envelope numbers
- Feed reads:
- Posts: , roughly a 50:1 read-to-write ratio
- Timeline writes if fanning out on write:
- Media:
The 50:1 read-to-write ratio tells us to optimize the read path. At the same time, 240k timeline writes per second is a large number in its own right, which is an early warning that precomputing feeds at write time carries a real cost.
High-level architecture
- Object storage. Photos and videos upload directly via presigned URLs. Bytes never pass through your servers.
- Post service. Writes post metadata and publishes a
PostCreatedevent. - Post store. The durable record of every post, partitioned by user.
- Fan-out queue. Decouples posting from the expensive follower fan-out.
- Fan-out workers. Look up followers and push the post ID into each of their timelines.
- Timeline cache. A per-user list of recent post IDs, held in memory.
- Feed service. Reads the timeline list and hydrates each post with its content and counts.
- CDN. Serves the actual media, which is the overwhelming majority of bytes.
Deep dive 1: fan-out on write versus fan-out on read
This is the question, and interviewers expect you to raise both sides before choosing.
Fan-out on write (push). When a user posts, immediately write the post ID into every follower's timeline list. Reads become trivial: fetch a list, hydrate it, done. Writes cost O(followers).
Fan-out on read (pull). Store nothing extra. At read time, look up who the user follows, fetch recent posts from each, and merge. Writes are trivial; reads cost O(following) queries and a merge, on every app open.
With a 50:1 read-to-write ratio, push wins by default. You do the expensive work 1,200 times a second instead of 60,000 times a second, and the read path becomes a cache lookup.
Deep dive 2: the celebrity problem
Push breaks on exactly one input: an account with 400 million followers. One post becomes 400 million timeline writes, which will saturate your fan-out fleet and delay everyone else's posts behind it. A single celebrity can add minutes of lag to the entire system.
The answer is a hybrid. Fan out on write for normal accounts, and skip fan-out entirely for accounts above a follower threshold. At read time, the feed service merges the user's precomputed timeline with a live pull of recent posts from the handful of celebrity accounts they follow. Celebrity posts are the most-cached objects in the entire system, so pulling them is cheap.
Two details earn extra credit. The threshold is a tunable number rather than a constant, so say roughly a million followers and note that you'd tune it against fan-out lag. And the merge happens on a small number of accounts, since even users who follow many celebrities follow only a few dozen.
Deep dive 3: what the timeline actually stores
Store post IDs, not post content. A timeline entry should be an ID and a timestamp, so the list stays small enough to keep entirely in memory. The feed service then hydrates those IDs against the post cache in a single batch lookup.
This matters because content changes and IDs don't. If you denormalize post content into every follower's timeline, an edited caption or a deleted post means finding and rewriting millions of copies. With IDs, a deletion is a single write plus a filter at hydration time.
Put an upper bound on the length of each timeline, so that memory stays predictable as the user base grows. Very few people scroll past a few hundred posts, so cap the list around there and serve anything older from a pull query against the post store. The memory this costs across the fleet is predictable and computable: , which is large but tractable.
Deep dive 4: storing and serving media
As we saw in the estimation step above, images and video in an app like Instagram add up to roughly 200 TB per day. Files of that size don't belong in your application database, and they shouldn't pass through your application servers either, since a single upload would occupy a request thread for seconds and consume bandwidth you need for everything else.
Instead, the client uploads directly to object storage using a presigned URL issued by your API. Your servers handle only the small metadata write. Once the upload completes, an event kicks off a processing pipeline that generates thumbnails and several display resolutions, and playback is served through a CDN so the bytes travel from an edge location rather than from your origin. This is the media streaming pattern applied at a smaller scale.
Deep dive 5: Scaling to 10x traffic
Three things degrade first, and naming them in order is a strong close to the interview.
- The fan-out fleet falls behind during peak posting hours. Detect this with the age of the oldest queued fan-out job rather than raw queue depth, since depth alone doesn't tell you how stale anyone's feed is.
- Timeline cache memory becomes the binding constraint. This is what the per-timeline length cap protects against.
- Hot posts concentrate hydration traffic on single cache keys. A post from a very large account is requested by millions of users at once, which wants that key replicated across cache nodes.
Common pitfalls
- Choosing fan-out on write without raising the celebrity case. This is the single most-tested follow-up in the question.
- Storing post content in timelines. Edits and deletions become a distributed find-and-replace.
- Routing media through the app tier. Presigned uploads and CDN delivery, always.
- Unbounded timelines. Memory grows without limit for users who follow thousands of accounts.
- Synchronous fan-out. Posting should not wait on 200 timeline writes.
Leveling the answer
Related lessons
Build a timeline of posts from followed accounts, plus trending topics.
Rank and serve a homepage of posts that reorders as votes come in.