System Design
Design Instagram
Photo sharing sounds simple until you hit the feed. Generating a personalized timeline for hundreds of millions of users - including the one who follows a celebrity with 200 million followers - is where this question gets hard. Here's the answer interviewers are looking for.
"Design Instagram" - a photo-sharing service where users post images, follow others, and see a feed of posts from people they follow - sounds approachable, and the first half is. Storing photos, following users: manageable. Then you reach the feed, and the question reveals its teeth. Generating a personalized, real-time feed for hundreds of millions of users is one of the genuinely hard problems in system design, and it's the part that separates a competent answer from a great one.
I've watched this question for years from the interviewer's chair. Let me walk through how to approach it - and, since I'm the one scoring it, exactly where the feed problem makes or breaks the answer.
Scope the core
As always, narrow first. The functional core of Instagram:
- Post a photo (with a caption).
- Follow other users.
- See a feed of recent posts from the people you follow.
- Like and comment on posts.
Defer the rest - stories, direct messages, explore, reels - unless the interviewer asks. Then the non-functional requirements:
- Massively read-heavy. People scroll their feed constantly; they post far less often. Reads vastly outnumber writes.
- Low latency - the feed must load fast, or people leave.
- High availability and the ability to scale to hundreds of millions of users.
- Media-heavy - photos are large, and there are billions of them.
Interview: Two observations early tell me a candidate understands this problem: that it's read-heavy (feeds are read far more than posts are created), and that it's media-heavy (we're storing and serving enormous numbers of large image files). Each drives a major design decision. Candidates who name both up front have framed the problem correctly; candidates who treat it like a balanced text-based app are about to design the wrong system.
The easy half: posting and storing photos
Let's handle the part that's genuinely straightforward, because doing it cleanly earns trust before the hard part.
When a user posts a photo, we don't store the image in our main database - that would be slow and expensive. Instead, the image goes into object storage (blob storage built for large files), and the database stores just the metadata: who posted it, when, the caption, and a reference (URL) to the image in object storage. This separation - big binary files in object storage, structured metadata in the database - is the standard, correct approach, and getting it right signals you know how media is actually handled.
For serving those photos fast to users worldwide, we put a CDN in front of the object storage, so images are cached close to users rather than fetched from a distant origin every time. Images are large and viewed enormously more often than they're uploaded, so serving them from an edge location near the user - instead of a single distant origin - is exactly the kind of latency win the CDN exists for. (These are building blocks from the foundation - object storage and CDN - applied exactly where they belong.)
graph TD
U[User posts photo] --> APP[App Server]
APP --> OBJ[(Object Storage<br/>the image file)]
APP --> DB[(Database<br/>metadata: user, caption, image URL)]
OBJ --> CDN[CDN serves images<br/>close to users]
V[Viewer] --> FEED[Feed Service]
FEED --> DB
FEED --> CDN
This diagram shows Instagram's posting and serving paths. When a user posts a photo, the app server stores the actual image file in object storage and stores only the metadata - user, caption, and image URL - in the database. A CDN sits in front of object storage to serve images close to users. When a viewer loads their feed, the Feed Service reads metadata from the database and the images come from the CDN.
The hard half: generating the feed
Now the real question. A user opens the app and expects to see recent posts from everyone they follow, ordered by time, loaded instantly. How do you build that feed?
The naive approach (fan-out on read): when a user opens their feed, query for all the people they follow, fetch the recent posts from each, merge them, sort by time, and return. This is simple and always current - but it's slow at read time, especially for users who follow many people, and it does this expensive work on every single feed load. Since the system is read-heavy, doing heavy work on every read is exactly backwards.
The better approach for most users (fan-out on write): precompute feeds. When a user posts, immediately push that post into the feeds of all their followers - so each user has a pre-built feed sitting ready. Then loading the feed is just reading that prepared list: extremely fast. We move the work from read time (frequent) to write time (less frequent), which fits a read-heavy system perfectly. Each user has a "feed" - essentially a cache of post references - that's updated whenever someone they follow posts.
graph LR
P[User posts] --> FO[Fan-out on write]
FO --> F1[Push into follower 1's feed]
FO --> F2[Push into follower 2's feed]
FO --> F3[Push into follower 3's feed]
R[Follower opens app] --> READ[Read pre-built feed - fast]
This diagram shows fan-out on write. When a user posts, the system fans the post out, pushing it into each of their followers' pre-built feeds. Later, when a follower opens the app, their feed is already built, so reading it is fast. The work happens at write time rather than on every read.
Interview: The feed is the crux of this interview. A candidate who only describes fan-out on read (query everyone you follow at load time) has the correct but naive answer - it works but doesn't scale for a read-heavy system. A candidate who proposes fan-out on write (precompute feeds when people post) shows they understand how to optimize for the read-heavy reality. But the answer that earns the top score is the one that anticipates the problem with fan-out on write - the celebrity problem - before I raise it. That's the next section, and it's the single most revealing follow-up in this entire question.
The celebrity problem
Here's the elegant trap in fan-out on write, and the follow-up I always ask: what happens when a celebrity with 200 million followers posts?
Fan-out on write means pushing that single post into 200 million feeds - an enormous, slow, expensive write amplification for one post. If you fan out every celebrity post to hundreds of millions of feeds, the write load becomes crushing. Pure fan-out on write breaks down precisely for the most-followed accounts.
The standard solution is a hybrid approach:
- For most users (normal follower counts), use fan-out on write - precompute their followers' feeds, since the fan-out is cheap.
- For celebrities (huge follower counts), don't fan out their posts. Instead, when a user loads their feed, fetch the precomputed feed and pull in recent posts from any celebrities they follow at read time (fan-out on read for those few accounts), merging the two.
This hybrid gets the best of both: fast precomputed feeds for the common case, without the catastrophic write amplification of fanning a celebrity's post to hundreds of millions of feeds. The handful of celebrity accounts a user follows are cheap to pull at read time; everyone else's posts are already in the precomputed feed.
Interview: The celebrity problem is, for me, the single most diagnostic moment in this question. A candidate who designs pure fan-out on write and doesn't see the celebrity issue until I point it out has a gap. A candidate who proactively says "...but fan-out on write breaks for celebrities with millions of followers, so I'd use a hybrid - fan-out on write for normal users, fan-out on read for celebrities" has demonstrated the exact kind of edge-case thinking that distinguishes a senior engineer. It's a small phrase that carries enormous signal: it shows you don't just know the happy-path pattern, you know where it fails and how to fix it.
Deep dive: likes and comments at scale
Likes and comments seem trivial, but at Instagram's scale they have their own twist worth raising. A wildly popular post can receive millions of likes, and showing an exact, real-time like count on a post viewed by millions creates enormous write and read pressure on whatever stores that count. Updating a single counter row millions of times, while millions of people read it, is a contention hot spot.
The pragmatic approaches: store likes in a way that can be aggregated rather than contended on a single row, and accept that the displayed count can be approximate or slightly delayed for extremely popular posts - nobody needs a celebrity post's like count to update with perfect precision in real time. Comments are stored separately and typically paginated (you load the most recent, not all million). A candidate who notes that exact real-time counts on viral content create a hot spot, and that approximate or eventually-consistent counts are an acceptable trade, is showing the kind of judgment about consistency-versus-scale that this question can surface.
Deep dive: ranking the feed
I often ask whether the feed should be strictly chronological or algorithmically ranked, because it changes the design. A purely chronological feed (newest first) is simpler - the precomputed feed is just ordered by time. An algorithmic feed - showing the posts predicted to be most engaging, not strictly newest - adds a ranking layer that scores candidate posts using signals (engagement, relationship, recency) before presenting them. This means feed generation isn't just "merge and sort by time"; it's "gather candidate posts, then rank them." You don't need to design the ranking model, but recognizing that an algorithmic feed inserts a scoring step between gathering posts and showing them - and that this interacts with the fan-out strategy (you're now ranking the candidates, not just ordering them) - shows you understand how real feeds work beyond the basic timeline.
Deep dive: caching the read path
Because the system is so read-heavy, caching deserves explicit attention on the feed-read path. The precomputed feeds themselves are essentially a cache (of post references per user), but you'd also cache the actual post content and user data that feeds reference, so assembling a feed for display doesn't require many separate database lookups. Popular posts, popular users' profiles, and frequently accessed feeds all benefit from caching. The images, of course, are already served from the CDN. The throughline is that almost every layer of the read path - feed, post metadata, images - is cached, because in a system where reads dwarf writes by orders of magnitude, serving reads from memory rather than the database is the difference between a fast feed and a slow one. (See the caching guide for why this is the highest-leverage move in read-heavy systems.)
A note on estimating the scale
Grounding the design in numbers helps. Suppose hundreds of millions of users, each opening their feed many times a day - that's billions of feed reads daily - against a far smaller number of posts created. The read-to-write ratio is enormous, which is the entire justification for precomputing feeds (fan-out on write) and caching aggressively: you optimize relentlessly for the read path because reads dominate by orders of magnitude. On the media side, billions of photos, each potentially viewed many times, justifies the object-storage-plus-CDN approach for serving them efficiently worldwide. Stating these magnitudes shows the interviewer you're designing for Instagram's actual scale, where the read-heavy, media-heavy numbers force every major decision.
Tying it together
The full design:
- Posting: images to object storage, metadata to the database, served via CDN.
- Following: a straightforward relationship between users.
- Feed: hybrid fan-out - precompute feeds on write for normal users, pull celebrity posts at read time, merge.
- Scale: the read-heavy nature handled by precomputation and caching; the media handled by object storage and CDN; the data layer scaled with replicas and sharding as it grows.
| Concern | Decision | Why |
|---|---|---|
| Photo storage | Object storage + CDN | Large files; serve fast worldwide |
| Metadata | Database (references, not images) | Structured queries, small rows |
| Feed (normal users) | Fan-out on write (precompute) | Read-heavy; move work to write time |
| Feed (celebrities) | Fan-out on read (hybrid) | Avoid fanning to millions of feeds |
| Scale | Caching, replicas, sharding | Hundreds of millions of users |
Interview: What gets you hired on "Design Instagram": framing it as read-heavy and media-heavy up front, separating image storage (object storage + CDN) from metadata cleanly, and - above all - handling the feed with fan-out on write and recognizing the celebrity problem that forces a hybrid. The candidates who struggle are the ones who get stuck on fan-out on read and never optimize for the read-heavy reality, or who design pure fan-out on write and never see it break for celebrities. Nail the feed, with its edge case, and you've nailed the question.
The bottom line
Designing Instagram is easy until the feed. Photos go to object storage with metadata in the database and a CDN out front - clean and standard. The feed is the hard part: fan-out on read is correct but doesn't scale for a read-heavy system, fan-out on write precomputes feeds to fit that read-heavy reality, and the celebrity problem (fanning one post to hundreds of millions of feeds) forces a hybrid - precompute for normal users, pull celebrity posts at read time. That hybrid, and the edge-case thinking behind it, is the heart of a strong answer. The surrounding details - likes and comments as potential hot spots, chronological versus algorithmic ranking, and caching every layer of the read path - round out a design that takes the read-heavy, media-heavy nature seriously throughout.
Frame the problem by its read-heavy and media-heavy nature, handle media with the right building blocks, and treat the feed - with its celebrity edge case - as the centerpiece, and this question becomes a showcase of how you reason about scale. The pattern generalizes well beyond Instagram: Twitter/X, Facebook, TikTok, and almost every social feed face the same fan-out-versus-celebrity tension, so mastering it here equips you for the entire family of feed-design questions. We work through case studies like this end to end across System Design Fundamentals.
Go deeper
- The System Design Primer - includes feed design and the fan-out patterns.
- Fan-out (software) (Wikipedia) - the concept behind feed precomputation.
- Designing Data-Intensive Applications - the deep reference for the data and feed-generation challenges.
- Amazon Builders' Library - how read-heavy, media-heavy services are built at scale.