- Published on
- Views
Design a News Feed System Design Interview Guide
- Authors

- Name
- Javed Shaikh
← System Design Interview Preparation
This guide walks through Design a News Feed the way you would in a backend or Java interview. The numbers are interview estimates. They help you show your thinking. They are not a production capacity plan.
1. Problem
A news feed shows a user new posts from people they follow, in a useful order, with pagination.
Example:
- You follow 200 people
- They post photos and text during the day
- When you open the app, you see a ranked list: recent, interesting, not already seen
This is the Instagram / Twitter / LinkedIn home timeline problem. It looks simple. The hard part is fan-out: one post from a popular user must reach millions of follower timelines without melting the database.
In this design we are building a system that:
- Lets users create posts
- Stores a follow graph
- Builds a home timeline
- Ranks and paginates that timeline
We are not building stories, ads targeting, or a full social network. We are designing post + follow + feed.
2. Functional Requirements / FR
| Requirement | What it means |
|---|---|
| Create post | Text, maybe media ids. Owner is the logged-in user. |
| Follow / unfollow | Directed graph: A follows B. |
| Home feed | Posts from people I follow (and maybe my own). |
| Pagination | Infinite scroll with a cursor, not OFFSET 100000. |
| Ranking basics | Recency plus simple signals (likes, time decay). Not a full ML platform. |
| Seen / new | Optional. Prefer not showing the same post twice in one session. |
Out of scope for a 45-minute interview:
- Full ads auction
- Live video
- Detailed privacy graphs beyond public/followers
- Multi-country ranking models
Ask if the feed is reverse chronological first. Add ranking as a second step. Interviewers like that order.
3. Non-Functional Requirements / NFR
| Requirement | Why it matters |
|---|---|
| Fast feed reads | Opening the app is the most common action. Aim for low hundreds of milliseconds. |
| Write fan-out cost | Celebrity posts cannot synchronously update 50 million timelines. |
| High availability | Feed down means the app feels dead. |
| Eventual consistency | A post can appear on follower feeds a second later. That is usually fine. |
| Pagination stability | New posts should not shuffle the page the user is staring at too wildly. |
A good interview sentence: reads must be precomputed or very well indexed. You cannot join follow-graph × posts on every app open.
4. Back-of-the-Envelope Calculation
Traffic assumptions
- 500 million users, but 100 million Monthly Active Users
- 50 million Daily Active Users
- Each DAU opens the feed 10 times a day → 500 million feed reads / day
- Each DAU creates 1 post every 2 days → ~25 million posts / day
- Average user follows 200 people
- Read/write ratio (feed reads vs posts) ≈ 500M / 25M = 20 : 1
Feed reads dominate. Posts are the expensive write if you fanout on write.
QPS
Feed read QPS:
500,000,000 / 86,400 ≈ 5,800 QPS
Peak 5× → around 30,000 QPS.
Post create QPS:
25,000,000 / 86,400 ≈ 290 QPS
Peak posts ≈ 1,500 QPS.
If we fanout on write to 200 followers on average:
1,500 posts/sec × 200 timeline writes ≈ 300,000 timeline writes/sec at peak
That number is why this problem is famous. Average is fine. Celebrity users are not average.
Storage
Post body ≈ 1 KB (text + metadata; media in object storage)
25,000,000 × 1 KB ≈ 25 GB/day of post rows
One year ≈ 9 TB. Sharded post store is required at this scale. For the interview, say posts in a distributed DB, media in object storage.
Feed store: each timeline entry is postId + authorId + score + time ≈ 64 bytes.
If we keep 500 posts per user inbox for 100 million MAU:
100,000,000 × 500 × 64 bytes ≈ 3.2 TB
Cache the active users’ first page in Redis.
Cache / memory estimate
5 million users online in a peak hour. First page = 20 entries × 64 bytes ≈ 1.3 KB, plus post bodies for those 20 × 1 KB ≈ 20 KB. Round to 25 KB per hot user.
5,000,000 × 25 KB ≈ 125 GB
That is a Redis cluster, not one box. Cache ids + hydrated posts for the first page only.
Server estimate
Feed read service at 2,000 QPS per instance (mostly cache):
30,000 / 2,000 ≈ 15 feed servers
Use ~20. Post service can be a few more. Workers scale with fanout, not with user QPS.
These are interview estimates, not exact production numbers.
5. APIs
Create post
POST /api/posts
{
"text": "Shipping a URL shortener write-up",
"mediaIds": []
}
201:
{
"postId": "p_9k2",
"userId": "u_42",
"createdAt": "2026-09-19T08:00:00Z"
}
Follow
POST /api/follows
{ "followeeId": "u_99" }
DELETE /api/follows/u_99 to unfollow.
Home feed
GET /api/feed?cursor=...&limit=20
{
"items": [
{
"postId": "p_9k2",
"userId": "u_99",
"text": "Shipping a URL shortener write-up",
"createdAt": "2026-09-19T08:00:00Z",
"likeCount": 128
}
],
"nextCursor": "eyJ0IjoxNzcwMDAwfQ"
}
Use a cursor (timestamp + post id), not offset.
User profile posts
GET /api/users/:id/posts — this is fanout-on-read friendly: one user’s posts, indexed by user id.
6. Data Model
users
user_id, name, created_at. Normal user service.
follows
| Field | Notes |
|---|---|
follower_id | who follows |
followee_id | who is followed |
created_at |
Indexes: (follower_id) for “who I follow”, (followee_id) for “my followers” (fanout).
posts
| Field | Notes |
|---|---|
post_id | unique |
user_id | author |
text | |
media_ids | |
created_at | |
like_count | approximate is fine |
Index (user_id, created_at desc) for profile pages.
feed_timeline (inbox)
| Field | Notes |
|---|---|
owner_id | the reader |
post_id | |
author_id | |
score | ranking |
created_at |
Primary pattern: (owner_id, created_at desc) or a Redis list/ZSET per user.
Do not store full post text in every follower inbox. Store ids, then hydrate.
7. High-Level Design
Posts are saved first. A worker then pushes them into follower feeds. Readers load a prebuilt timeline from the feed store and cache.
News Feed architecture
Components:
- User (writer): publishes a post.
- Post Service: validates and stores the post. Publishes a
PostCreatedevent. - Post DB: source of truth for post bodies.
- Queue: buffers fanout work so create API stays fast. See Kafka style pipelines.
- Feed Worker: loads followers, writes timeline entries, skips or special-cases celebrities.
- Feed Store: per-user inbox (Redis ZSET, Cassandra, etc.).
- Reader: opens the app.
- Feed Service: reads inbox ids, hydrates posts, applies light ranking, uses cache for page 1.
- Cache: hot first pages and hot post bodies.
Create flow:
- Save post.
- Return 201 quickly.
- Emit event.
- Worker fans out to follower inboxes (hybrid for celebrities).
Read flow:
- Load timeline ids for the user.
- Hydrate posts (cache first).
- Return page + cursor.
8. Deep Dives
Follow graph
It is directed. A follows B does not mean B follows A.
Keep this store optimized for two queries:
- Followees of me — mix of fanout-on-read
- Followers of me — fanout-on-write
Cache follower lists for users who post often, but celebrity follower lists are huge. Do not load 50 million ids into one worker payload. Page through them.
Fanout on write vs fanout on read
Fanout on write (push): when I post, write that post id into each follower’s inbox.
- Read is fast: just read my inbox
- Write is heavy for celebrities
- Storage duplicates ids
Fanout on read (pull): when I open the feed, fetch latest posts from each person I follow and merge.
- Write is cheap: one post row
- Read is heavy: 200 user queries and a merge every time
- Fine for users who follow few people
Hybrid (the interview answer):
- Regular users: push to follower inboxes
- Celebrity users (follower count > N, say 1 million): do not push. Readers pull that celebrity’s latest posts and merge them in at read time
This is the celebrity user problem.
Feed generation
Worker pseudologic:
- Read
PostCreated - Get author follower count
- If celebrity, stop (or write to a “celebrity posts” store)
- Else page through followers and batch-insert timeline ids
- Trim each inbox to last 500–1000 posts
- Invalidate that user’s feed cache if they are online
Use a queue so a slow fanout cannot block posting.
Timeline storage
Redis ZSET: feed:{userId} score = timestamp or rank score, member = postId. Very fast for page 1. Memory-heavy. Often used for online users only.
Cassandra / Dynamo: partition by owner_id, sort by time. Cheaper for the long tail of inactive users.
A common split: Redis for hot users, disk KV for cold inboxes.
Ranking basics
Do not claim a neural net in 45 minutes.
Simple score:
score = time_decay + 0.001 * likes + 0.01 * comments
Time decay keeps the feed fresh. Likes push good posts up a little.
You can rank at write (score stored on the inbox entry) or at read (fetch 2 pages, sort, return 1). Read-time rank is more flexible. Write-time rank is cheaper at 30k QPS.
For interviews: generate a reverse-chronological inbox, then apply a light rank on the latest K items.
Celebrity user problem
If a user has 50 million followers, fanout-on-write is 50 million inbox writes. That can take minutes and flood the cluster.
Treat them as broadcast:
- Store their posts in a celebrity timeline
- At read, merge
my inbox+latest posts from celebrities I follow - Cache celebrity latest posts heavily
Also rate-limit how often a celebrity can trigger notifications. The feed can still show the post.
Hydration
Inbox has ids. Feed service batches MGET post:id1, post:id2, ... from cache, then DB for misses. Never N+1 query each post.
9. Bottlenecks
| Bottleneck | What happens | What you do |
|---|---|---|
| Celebrity fanout | Queue lag, worker lag | Hybrid push/pull |
| Feed QPS | App open storm in the evening | Cache page 1. More feed servers. |
| Hydration | 20 posts × DB round trips | Batch + cache post bodies |
| Follow graph hot read | Popular user posts, workers stampede the follow table | Cache sharded follower lists |
| Inbox trim | Unbounded Redis memory | Cap 500–1000 items |
| Ranking on full history | Too slow | Rank only the candidate set |
The first bottleneck to name is fanout for popular users.
10. Tradeoffs
Push vs pull vs hybrid
- Push: great reads, painful celebrity writes
- Pull: great writes, painful reads
- Hybrid: extra merge logic, best practical answer
Precompute vs compute on read
Precompute (inbox) costs storage and workers. Compute on read costs latency. At large DAU, precompute the normal case.
Strong vs eventual consistency
Followers can see a post a few seconds late. After you post, you should see it on your profile immediately from Post DB, even if fanout lags.
SQL vs wide-column for inboxes
SQL is fine for a small app. At this scale, interviewers expect Redis/Cassandra for timelines and a normal DB for posts.
11. Failure Modes
Fanout queue down
Users can still post (if Post DB is up). Feeds lag. Show the author’s own post from Post DB. Replay the queue later.
Feed store down
Fall back to fanout-on-read for a degraded feed: last 20 followees only, or a cached copy.
Duplicate posts in feed
Worker retries. Use post_id uniqueness per inbox. Idempotent writes.
Unfollow still showing posts
Delete that author’s entries from the inbox asynchronously. Until then, filter at read time by current follow set for the first page.
Hot celebrity merge slow
Cache celebrity recent posts. Limit how many celebrities you merge (people rarely follow 500 celebrities).
Pagination jumping
Use cursors. Do not use offset. New posts appear on a refresh, not in the middle of an old page.
12. Interview Answer in 10 Minutes
Here is a version you can speak out loud.
"I would design a news feed as a read-heavy system with a hybrid fanout.
Assume 50 million daily users, 10 feed opens each, and 25 million posts a day. Feed reads are about 5,800 QPS, around 30,000 at peak. Posts are only a few hundred QPS, but if I push each post to 200 followers, peak timeline writes can hit hundreds of thousands per second. Celebrity users make that much worse, so I will not push to every follower for them.
Posts go to a post service and post DB. A Kafka-style queue carries PostCreated events. Workers write post ids into each regular follower’s inbox, a Redis ZSET or Cassandra timeline, trimmed to a few hundred entries. Celebrity posts stay on the author’s timeline and are merged at read time.
When a reader opens the app, the feed service loads their inbox, hydrates post bodies from cache, merges a few celebrity posts, applies a simple recency-plus-likes rank on the candidate set, and returns a cursor page.
If the queue is slow, posting still works and feeds catch up. If cache misses, we batch-load the post DB. The create API never waits on 50 million inbox writes.
That is the design: post store, follow graph, hybrid fanout, inbox + cache, light ranking."
Practice this until it is under 10 minutes.
13. Interview Talking Points
- Do not join follows and posts on every read at scale.
- Hybrid fanout is the celebrity answer.
- Async workers keep
POST /postsfast. - Store ids in the inbox, hydrate in batch.
- Cursor pagination.
- Light ranking on a candidate set, not the whole history.
- Cache page 1 for online users.
- Event-driven fanout fits event-driven architecture.
14. Follow-up Questions
How do you handle 50 million followers?
Do not fanout-on-write. Pull celebrity posts at read time and cache them.
How do you rank without ML?
Time decay + social proof on the latest K posts. Mention ML as a later ranking service.
What if I unfollow someone?
Filter on read immediately. Clean inbox in the background.
How do media uploads work?
Upload to object storage first, then create post with media ids. Feed stores ids, not bytes.
Can this run on Spring Boot + Kafka?
Yes: post API in Spring, Kafka for PostCreated, consumers write inboxes. See scaling Java event-driven systems.
Other probes: mute words, seen-state, and multi-device pagination.
15. Internal Links
Related JavaThoughts reading:
- System Design Interview Preparation
- Design a Distributed Cache
- Design a Notification System
- Kafka
- Event-driven architecture
- Message queues
- Java
- Spring Boot
- Microservices
- Distributed Systems
- 20 system design concepts
Next in this series: Design a Chat Messaging System.
