Design Instagram
You're asked to design a social photo-sharing app like Instagram, usually scoped to posting and the home feed. Users upload photos, and their followers see those photos in a personalized feed that loads in under a second. The system may hold billions of posts, but each feed needs only the recent ones that matter to that user.
The hard part is deciding when to build the feed. Assembling it from scratch on every read does not scale to hundreds of millions of daily users. Building every feed ahead of time works well until an account with 400 million followers publishes a post. Let's compare those approaches and arrive at a practical compromise.
Clarify the requirements
- Which surfaces are in scope? Instagram includes posting, the home feed, search and explore, stories, direct messages, and reels. You cannot cover all of them in one interview. Start with posting and the home feed, then let the interviewer redirect if needed.
- Is the feed chronological or ranked? A reverse-chronological feed requires a merge. Ranking adds a scoring layer and changes what the system can precompute.
- How fresh should the feed be? Ask whether new posts must appear within seconds or whether a minute is acceptable. That freshness budget guides the rest of the design.
- How are followers distributed across accounts? Most accounts have an ordinary number of followers, while a few have hundreds of millions. That distribution will force a hybrid design.
For this design, assume that posting, media, and a reverse-chronological home feed are in scope. New posts should appear within seconds.
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 points toward optimizing reads. But 240k timeline writes per second is still substantial, so precomputing feeds will not be free.
High-level architecture
- Object storage. Photos and videos upload directly through presigned URLs, so the bytes never pass through the application servers.
- Post service. Writes post metadata and publishes a
PostCreatedevent. - Post store. Holds 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. Keeps an in-memory list of recent post IDs for each user.
- Feed service. Reads the timeline list and hydrates each post with its content and counts.
- CDN. Serves the media, which accounts for most of the system's bandwidth.
Deep dive 1: fan-out on write versus fan-out on read
The central choice is whether to build timelines when posts are written or when feeds are read. Both approaches have a clear cost.
Fan-out on write (push). When a user posts, write the post ID into every follower's timeline. Reading the feed is then a matter of fetching a list and hydrating its posts. The write costs O(followers).
Fan-out on read (pull). Store no extra timeline data. When a user opens the app, look up the accounts they follow, fetch recent posts from each one, and merge the results. Writes are cheap, but every feed read requires O(following) queries and a merge.
With a 50:1 read-to-write ratio, push is the better default. The system does the expensive work 1,200 times per second instead of 60,000, and most feed reads become cache lookups.
Deep dive 2: the celebrity problem
Push runs into trouble with accounts that have enormous followings. A post from an account with 400 million followers creates 400 million timeline writes. That can saturate the fan-out fleet, leave other posts waiting in the queue, and add minutes of lag across the system.
A hybrid handles both cases. Use fan-out on write for ordinary accounts, but skip it when an account exceeds a follower threshold. At read time, the feed service merges the user's precomputed timeline with recent posts pulled from the celebrity accounts they follow. Those posts receive so much traffic that they are likely to be in cache, which keeps the pull cheap.
Treat the threshold as a tuning parameter rather than a fixed constant. Roughly one million followers is a reasonable starting point, then adjust it based on observed fan-out lag. The read-time merge also stays manageable because even users who follow many celebrities usually follow only a few dozen of them.
Deep dive 3: what the timeline actually stores
Store post IDs, not post content. Each timeline entry needs only an ID and a timestamp, which keeps the list small enough to hold in memory. The feed service can hydrate a batch of IDs from the post cache in one lookup.
Post content can change, but IDs do not. If every follower's timeline contains a copy of the post, editing a caption or deleting the post requires finding and rewriting millions of entries. With ID-only timelines, deletion takes one write, followed by a filter when the feed hydrates its posts.
Cap the length of each timeline so memory use remains predictable as the user base grows. Few people scroll past a few hundred posts, so keep roughly that many entries in memory and fetch anything older from the post store. The total memory requirement is straightforward to estimate: . That is large, but tractable across a fleet.
Deep dive 4: storing and serving media
Images and video add roughly 200 TB per day at the scale estimated above. They do not belong in the application database or on the path through the application servers. A single upload could occupy a request thread for seconds and consume bandwidth needed by the rest of the service.
The client should upload directly to object storage with a presigned URL from the API. The application servers then handle only the small metadata write. After the upload finishes, an event starts a processing pipeline that generates thumbnails and several display resolutions. A CDN serves the finished media from an edge location instead of sending every byte from the origin. This is the media streaming pattern at a smaller scale.
Deep dive 5: scaling to 10x traffic
At ten times the traffic, watch these three parts of the system first:
- The fan-out fleet may fall behind during peak posting hours. Track the age of the oldest queued fan-out job rather than raw queue depth. Queue depth alone does not reveal how stale the feeds have become.
- Timeline cache memory may become the binding constraint. The cap on timeline length keeps this growth under control.
- Hot posts can concentrate hydration traffic on individual cache keys. When millions of users request the same post, replicate its key across cache nodes.
Common pitfalls
- Choosing fan-out on write without addressing celebrity accounts. This is a common follow-up to the initial design.
- Storing post content in timelines. Edits and deletions become a distributed find-and-replace.
- Routing media through the app tier. Use presigned uploads and CDN delivery.
- 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 signals
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.