Understand the feed and size it
Part of the free System Design course on LogicWiz, in the chapter: Design a news feed. The interactive whiteboard exercises and simulations run in the app.
Week 14: The feed that was one SQL query
"The feed was a single query with a join. It flew with 20 users on my laptop. On launch day it timed out for everyone."
A SwiftKart intern, explaining why a feature was rolled back
What a home feed is, and what to ask first
SwiftKart's marketing team wants a social tab. People follow brands and friends, post photos of dinner, and see what others posted. Kabir tells Meera to treat it as its own app with 50 million daily users. The question is the classic one: design the home feed.
The home feed, also called the home timeline, is the list of recent posts from the accounts you follow. It opens when you open the app. Two things happen in this system. Publishing a post is the write path. Opening the feed is the read path.
Meera's first thought was simple: "A table of posts and one query. Posts where the author is someone I follow, newest first, limit 20." The query is correct in meaning. Whether it survives 50 million users is what the next sections measure.
Before drawing anything, ask the interviewer:
- Is the feed only accounts I follow, or also suggestions? (Assume only followed accounts.)
- Newest first, or ranked by a model? (Assume newest first. Ranking comes later.)
- How big is it, and how often do people open it? (Assume 50 million daily users, 10 opens each.)
- Do some accounts have millions of followers? (Yes: tens of millions.)
- How soon must a new post reach followers? (About 5 seconds is fine.)
- Photos and video? (Photos. Video is another chapter.)
Requirements, with numbers
Functional: publish a post (text plus up to four images); follow and unfollow; see a paginated home feed; see your own new post at once.
Non-functional:
- Feed load p99 under 200 ms on the server. The p99 is the time that 99 out of 100 requests beat. The first page holds 20 posts.
- A new post reaches followers' feeds in about 5 seconds. Feeds may lag a little and catch up. This is eventual consistency.
- Feed reads are 99.95% available. A slightly old feed beats an error page.
Out of scope for the core design: the ranking model, likes and comments, ads, moderation. We come back to ranking and likes later in this chapter.
Size it, step by step
Every box you draw later must be earned by one of these numbers.
- Feed reads: 50M users x 10 opens = 500M a day. 500M / 86,400 seconds is about 5,800 per second on average. The evening peak is roughly 3 times that: about 17,000 reads per second.
- Posts: say 10% of users post once a day. That is 5M posts a day, about 60 per second, and about 200 per second at peak. Reads outnumber posts by roughly 100 to 1.
- Copies if we push every post to every follower: an average author has about 200 followers. 5M posts x 200 = 1B feed inserts a day. That is about 12,000 per second on average and about 35,000 at peak.
- One creator with 20M followers: one post means 20M inserts. At 50,000 inserts per second that takes 400 seconds, almost 7 minutes.
- Storage: a post is about 1 KB, so 5M posts is 5 GB a day, about 1.8 TB a year. If 30% carry a 200 KB image, that is 1.5M x 200 KB = 300 GB a day, which belongs in object storage behind a CDN.
Meera's wrong belief: "200 posts per second is nothing. The database will cope." It is nothing for one write per post. But if each post is copied into 200 feeds, one post becomes 200 writes, and the celebrity case becomes 20 million. The post rate hides the real load. This is why interviewers wait for you to multiply by followers.
The API
POST /posts {text, mediaIds[]} -> 201 {postId}
POST /media/upload-url {contentType} -> 200 {uploadUrl, mediaId}
PUT /users/{id}/follow -> 204
DELETE /users/{id}/follow -> 204
GET /feed?cursor=&limit=20 -> 200 {posts[], nextCursor}
The app uploads images straight to object storage using a pre-signed URL, a short-lived link that allows one upload. The post service never carries image bytes.
For paging, use a cursor, not a page number. A cursor is a bookmark: the id of the last post you saw. Here is why. Rohan reads page 1, posts 100 down to 81. Five new posts arrive. With page numbers, "page 2" means "skip 20", but the list has shifted by 5, so he sees posts 85 to 81 again. With a cursor, the request says "older than post 81", and the answer is 80 down to 61 whatever arrived. Make post ids time-sortable, meaning ids that start with a timestamp, so sorting by id sorts by time.
The data model
- posts(post_id, author_id, text, media_ids, created_at): a wide-column or key-value store, partitioned by author so an author's timeline is one read.
- follows(follower_id, followee_id) and a mirror table followers(followee_id, follower_id). One answers "whom do I follow?", the other "who follows Rohan?".
- users(user_id, follower_count, is_celebrity): the flag is set when followers pass about 100K.
- feed store: for each user, a list of post ids, newest first, cut to the newest 500.
Store ids, not posts. 500 ids x 8 bytes is 4 KB per user, so 50M users need 200 GB of raw ids. A real cache adds its own overhead per entry, so plan for a small multiple of that. Full 1 KB posts would be 25 TB, and every edit would need rewriting in 200 places.
Write the plan in your own words before moving on.
📌 Summary: A feed has a write path and a read path. Peak is about 17,000 reads per second, but copying posts to followers makes about 35,000 writes per second. Page by cursor, store ids.
What Meera learns next
The numbers say reads need to be cheap and writes must not melt on one big account. Next: build the design box by box, starting from the simplest version and breaking it.
Check your understanding
- There are 5 million posts a day and an average author has 200 followers. If every post is copied into every follower's feed, what rate of inserts should you plan for at the evening peak?
- Rohan has read posts 100 down to 81. Five new posts arrive. The app asks for the next page using "skip 20". What does he see?
- A teammate wants each user's feed store to hold full 1 KB posts, to save a lookup on every read. 50 million users keep 500 entries each. Why is that a poor choice?
- In a mock, a candidate says every follower must see a new post the instant it is saved. What is the better requirement?