Lessons
1 · System Design Foundations
2 · APIs and Communication
3 · Capacity Estimation
4 · Core Building Blocks
5 · Databases
- 12Relational Databases and Data Modeling for System Design
- 13Database Indexes and Query Performance: How to Make Reads Fast
- 14Transactions, Isolation Levels and Concurrency Control: Preventing Race Conditions
- 15Database Replication: Primary-Replica, Read Replicas, Lag and Failover
- 16Database Sharding and Partitioning: How It Works and When You Need It
- 17SQL vs NoSQL: Data Models and How to Choose the Right Database
6 · Distributed Systems
- 18Why Distributed Systems Are Hard: Partial Failure, Timeouts and Clocks
- 19CAP Theorem and Consistency Models Explained Without the Myths
- 20Idempotency, Retries and Message Delivery Guarantees
- 21Distributed Transactions: Two-Phase Commit, the Outbox Pattern and Sagas
- 22Distributed Locks, Leases, Leader Election and Consensus
7 · Reliability and Operations
8 · Architecture and Security
9 · Interview Method and Foundation Case Studies
10 · Real-World Case Studies
- 33Design a Notification System: Email, SMS and Push at Scale
- 34Design a Chat System Like a Messaging App
- 35Design a News Feed: Fan-Out, Ranking and the Celebrity Problem
- 36Design Search Autocomplete (Typeahead)
- 37Design a Distributed Job Scheduler
- 38Design a Ticket Booking System Without Overselling
- 39Design a Payment System: Idempotency, Ledgers and Reconciliation
11 · Large-Scale Case Studies
- 40Design a Video Streaming Platform: Upload, Transcoding and Adaptive Streaming
- 41Design a Ride-Hailing System: Location, Matching and Real-Time Updates
- 42Design a Food Delivery Platform: Orders, Restaurants and Delivery Partners
- 43Design an E-Commerce System: Catalog, Cart, Checkout, Inventory and Flash Sales
- 44Design a Web Search Engine: Crawling, Inverted Indexes and Ranking
12 · Interview Readiness
Lesson 35 · Real-World Case Studies
Design a News Feed: Fan-Out, Ranking and the Celebrity Problem
Design a home feed that shows posts from accounts a user follows: estimates for posting, reading and fan-out, fan-out on read versus fan-out on write, the hybrid model that handles celebrity accounts, precomputed feed storage, hydration, ranking with a chronological fallback, cursor pagination, deletions and privacy, and what changes at social-media scale.
For
Candidates preparing for the news feed or timeline question at SDE-1 and SDE-2 level, and engineers building activity feeds.
Level
Before you start
Read Caching (article 09), Message Queues (article 11), Sharding (article 16) and Design a URL Shortener (article 30). Event-driven read models (article 27) explain the precomputed feed.
On this page
Key takeaways
- A feed can be assembled when it is read (fan-out on read) or precomputed when a post is made (fan-out on write); each fails at a different extreme.
- Fan-out on write gives fast reads for normal accounts but explodes for celebrities with millions of followers.
- The hybrid model pushes posts from normal accounts into followers' feeds and pulls celebrity posts at read time, merging the two.
- Store feeds as capped lists of post ids, hydrate them from caches at read time, and apply privacy and deletion checks during hydration.
- Ranking should degrade gracefully to chronological order, and every part of the pipeline is eventually consistent except a user's view of their own posts.
Open any social app and the first thing you see is a feed: recent posts from the people you follow, possibly reordered by what the app thinks you will care about. Pixly's feed was mentioned in almost every earlier article as "the hard read path". Here we finally design it.
The core difficulty is a fan-in, fan-out problem. A feed read needs posts from hundreds of accounts. A post must appear in the feeds of everyone who follows its author, which for most authors is a few hundred people and for a few celebrities is many millions. Every design choice in this case study is about where to pay that cost: when someone posts, or when someone reads.
What you will learn
#- How to estimate posting, reading and fan-out.
- Fan-out on read and fan-out on write, and where each breaks.
- The hybrid model for celebrity accounts.
- Storing precomputed feeds, and hydrating them at read time.
- Ranking, with a fallback to chronological order.
- Pagination, deletions, unfollows and privacy.
- What changes at social-media scale.
1. The problem
#Users follow other accounts (one-way, like most photo and microblogging apps). The home feed shows posts from followed accounts, newest or most relevant first, with infinite scrolling. Posts contain text and photos (photo files are already handled by object storage and a CDN, article 10).
2. Clarify the requirements
#Question | Assumed answer | Impact |
|---|---|---|
Follow model? | One-way follows; no limit on followers; following capped at 5,000 | Fan-out shape |
Celebrities? | Some accounts have tens of millions of followers | Hybrid model |
Ordering? | Ranked feed, with chronological as a fallback and an option | Ranking stage |
Freshness? | A new post appears in followers' feeds within about 10 seconds; the author sees it immediately | Eventual consistency, read-your-writes for the author |
Feed length? | Users rarely scroll past a few hundred items | Capped feed storage |
Private accounts and blocks? | Yes | Privacy checks on read |
Ads and recommendations from non-followed accounts? | Out of scope (mention as an extension) | n/a |
Functional requirements: create posts; follow and unfollow; read the home feed with pagination; show like and comment counts on each item.
Non-functional requirements
Quality | Target |
|---|---|
Feed latency | p99 under 300 ms for the first page |
Freshness | Followers see a new post within 10 seconds at p95 |
Availability | 99.95% for feed reads; a degraded feed is better than an error |
Correctness | Never show a post the viewer is not allowed to see; deleted posts disappear promptly |
3. Assumptions and scale estimation
#We start with Pixly's numbers from articles 06 and 07, then scale up in section 8.
10 million DAU; 50 million registeredFeed reads: 10 per DAU per day -> 100 million/day, about 1,160/s average, about 3,500/s peakPosts: 2 million/day -> about 23/s average, about 70/s peakAverage followers per posting account: 200 (median much lower; a long tail of large accounts)Fan-out on write (if every post is pushed to every follower): 2 million posts x 200 followers = 400 million feed insertions/day -> about 4,600/s average, about 14,000/s peakCelebrity: one account with 10 million followers posts once -> 10 million insertions from a single postFeed storage (precomputed): keep the latest 500 post ids per active user 10 million active users x 500 ids x 8 bytes = 40 GB (about 80 GB with structure overhead)Conclusions: reads (3,500 per second) need to be fast; fan-out on write is affordable on average (14,000 inserts per second at peak) but the celebrity tail is not; feed storage fits comfortably in an in-memory store.
4. API design
#GET /v1/feed?cursor=...&limit=20200 { "items": [ {"post_id": "p_8812", "author": {"id": 77, "name": "Meera", "avatar_url": "..."}, "caption": "Monsoon in Munnar", "media": [...], "like_count": 1203, "comment_count": 48, "liked_by_me": false, "created_at": "..."} ], "next_cursor": "opaque"}POST /v1/posts (idempotency key; returns 201 with post_id)PUT /v1/users/{id}/followers/me (follow, idempotent)DELETE /v1/users/{id}/followers/me (unfollow)DELETE /v1/posts/{id} (author only)The cursor is opaque (article 04). For a ranked feed, it identifies a position in a snapshot of the ranked list made for this browsing session, so scrolling does not skip or repeat items as new posts arrive.
5. Data model
#posts (post_id PK, time-ordered id; author_id; caption; media keys; visibility; created_at; deleted_at) index (author_id, created_at DESC) -> "this author's recent posts"follows (follower_id, followee_id, created_at) PK (follower_id, followee_id)followers (followee_id, follower_id) reverse index for fan-outuser_flags (user_id, is_celebrity, last_active_at, is_private)Feed store (precomputed), one entry per user: key: feed:{user_id} value: sorted set of post_id with score = created_at (or a ranking score) capped at 500 entries; expires if the user is inactive for 30 daysCounts: like and comment counters per post (cached, updated asynchronously, article 09)A sorted set per user is a natural fit for a feed of ids ordered by time or score: Redis sorted sets keep members ordered by score and support range reads, insertions and trimming efficiently (Redis sorted sets). The precomputed feed is a materialised view (Microsoft's Materialized View pattern describes such precomputed, query-optimised views and their eventual consistency (Materialized View pattern)), so it can always be rebuilt from posts and follows.
Partition keys: posts by post_id (and the author index by author_id); follows by follower_id; followers by followee_id; the feed store by user_id.
6. Baseline architecture: fan-out on read
#The simplest design builds the feed when it is requested:
GET /v1/feed: 1. followees = SELECT followee_id FROM follows WHERE follower_id = me (say 200) 2. for each followee: recent posts by author (from the author index or cache) 3. merge by time (or rank), take the top 20 4. hydrate: post details, authors, countsIt is always fresh, wastes no work on inactive users, and handles celebrities trivially (their posts are read like anyone else's). This is fan-out on read (also called the pull model).
7. What breaks first?
#At 3,500 feed reads per second with 200 followees each, step 2 alone is 700,000 author-timeline reads per second, and a user following 5,000 accounts makes a single feed request touch 5,000 timelines. Latency suffers (tail latency over many parallel reads, article 02) and the post store carries enormous read load for what is the same work repeated: the same popular authors' timelines read over and over.
The alternative, fan-out on write (the push model), moves the work to posting time: when a post is created, insert its id into every follower's precomputed feed. A feed read becomes one range read of feed:{me}, plus hydration. Reads are fast and cheap.
But fan-out on write breaks at the other end:
- Celebrities: one post from a 10-million-follower account creates 10 million inserts. At a few hundred thousand inserts per second it takes many seconds to minutes, delays everyone else's fan-out, and repeats with every post.
- Wasted work: many followers are inactive; pushing to their feeds is wasted.
- Write amplification: storage and network costs scale with followers, not with posts.
Fan-out on read (pull) | Fan-out on write (push) | |
|---|---|---|
Work happens | At read time | At post time |
Read latency | Higher; many parallel reads | Low; one range read |
Write cost | Low | Proportional to followers |
Celebrities | Easy | Very expensive |
Inactive users | No wasted work | Wasted pushes |
Freshness | Always current | Delayed by fan-out lag |
Best for | Users who follow few accounts; celebrity authors | Normal authors; frequently read feeds |
8. Scaling the design
#The hybrid model
#Combine the two:
- Normal authors (fewer than a threshold of followers, say 100,000): push each new post id into the feeds of active followers (active in the last 30 days).
- Celebrity authors (above the threshold): do not push. Their posts are pulled at read time.
- At read time: read the precomputed feed (pushed items) and the recent posts of the celebrities this user follows (usually a small number), merge, rank, and return.
REQUEST PATH (read)Client -> Feed service: 1. ZREVRANGE feed:{me} (pushed post ids, newest first) 2. celebrity followees of me (small list, cached) -> their recent post ids (cached per celebrity) 3. merge -> candidates -> rank (or sort by time) -> page of 20 4. hydrate: multi-get post objects, authors, counts, my-likes; filter deleted and not-allowed 5. return page + cursorASYNC PATH (write)Post service: insert post + outbox event "PostCreated" (article 21) -> Fan-out workers (if author is not a celebrity): page through followers (active only), ZADD post_id into each feed:{follower}, trim each feed to 500 entries -> Celebrity timeline cache updated (if author is a celebrity)Each celebrity's recent posts are cached once and read by millions of feed requests, so pulling them is cheap: it is a hot key served from cache (with local caches for the very hottest, article 09).
Fan-out workers
#- Consume
PostCreatedevents from a stream partitioned by author (article 11). - Read the author's followers in pages (for example 1,000 at a time) and write to feeds in batches (pipelining many
ZADDcalls). - Skip inactive followers; their feed is rebuilt on demand if they return (below).
- Be idempotent: adding the same post id to a sorted set twice is harmless, which makes redelivery safe.
- Scale with lag: at 14,000 inserts per second at peak, a modest pool of workers keeps fan-out lag within seconds.
Inactive and returning users
#If a user who was inactive for months opens the app, feed:{me} does not exist. Build it on demand with fan-out on read (the baseline algorithm) for the first request, store the result, and from then on the user receives pushes again. The first load is slower; every later load is fast.
Hydration
#The feed store holds only ids. Hydration turns 20 ids into a page:
- Multi-get post objects from a post cache (article 32), falling back to the database for misses.
- Multi-get author summaries and counts.
- Compute
liked_by_mewith one batched lookup. - Filter posts that are deleted, from blocked or private accounts the viewer may no longer see, or otherwise not allowed. Fetch a few extra ids to fill the page after filtering.
Hydration happens on every read, so it is the place to enforce rules that must be current (deletion and privacy), while the precomputed list may be slightly stale.
Ranking
#A ranked feed adds two stages:
- Candidate generation: the merged ids (pushed feed plus celebrity posts), a few hundred candidates.
- Scoring: compute a relevance score per candidate from features such as recency, the viewer's past interactions with the author, engagement on the post, and content type, using a model served by a ranking service with a strict latency budget (for example 50 ms).
Keep it robust:
- If the ranking service is slow or down, fall back to chronological order (circuit breaker, article 23). A slightly less relevant feed is far better than an error.
- Precompute expensive features offline (affinity between users, post quality signals) and keep them in a fast feature store.
- Snapshot the ranked list per session (store the ordered ids for the session briefly), so pagination is stable while new posts arrive.
Deletions, unfollows and edits
#- Deleted posts: marked deleted in
posts; hydration filters them immediately. A background job removes their ids from feeds lazily (or never; trimming removes them eventually). - Unfollow: future posts are no longer pushed. Existing items from that author can be filtered at read time (check the follow relationship for authors on the page) and cleaned up asynchronously.
- Privacy changes and blocks: enforced at hydration, so they take effect immediately even though feeds are precomputed.
The author sees their own post
#Read-your-writes (article 19): when a user posts, insert the id into their own feed synchronously (or merge "my recent posts" into my feed reads), so the author never wonders where their post went, while followers receive it via asynchronous fan-out.
Social-media scale
#Now suppose 500 million DAU, each reading the feed 15 times a day, and 100 million posts a day:
Feed reads: 7.5 billion/day -> about 87,000/s average, about 260,000/s at peak (factor 3)Posts: 100 million/day -> about 1,160/s average, about 3,500/s peakFan-out (normal authors, average 300 active followers): 3,500 x 300 = about 1 million inserts/s at peakFeed store: 500 million x 500 ids x 8 B = 2 TB (about 4 TB with overhead), sharded by user_idWhat changes:
- The feed store is a sharded cluster (article 32) of a few dozen to a hundred nodes, plus replicas; it may move to a disk-backed wide-column store with a cache in front, keeping only the most recent items in memory.
- Fan-out at a million inserts per second needs a large, autoscaled worker fleet reading from a partitioned stream, and an aggressive "active follower" filter.
- The celebrity threshold is tuned by measured cost: pushing to more than N followers costs more than pulling.
- Ranking becomes a major subsystem with its own feature pipelines, model training and serving; candidate generation also pulls in recommended posts from accounts the user does not follow (an extension beyond this design).
- Multi-region: feeds are built and stored per region near users; posts and follow graphs are replicated across regions asynchronously, so a post from another region appears a little later.
The final picture
#Clients -> CDN (media) ; API gateway -> Feed service -> feed store (sharded, by user) |-> celebrity timeline cache |-> ranking service (fallback: chronological) `-> hydration: post cache, user cache, counts cache, likesPost service -> posts DB -> outbox -> stream (partitioned by author) -> fan-out workers (normal authors -> active followers' feeds) -> celebrity timeline cache updaterFollow service -> follows/followers stores (sharded by follower and by followee)9. Failure scenarios and reliability
#Failure | Effect | Response |
|---|---|---|
Fan-out workers fall behind | Followers see new posts late | Feeds still serve; autoscale on lag; alert if p95 lag exceeds the freshness target |
Feed store node lost | Some users' feeds missing | Replicas; otherwise rebuild on read with fan-out on read for affected users |
Celebrity posts at peak | Potential fan-out storm | Hybrid model: celebrity posts are pulled, never pushed |
Hot celebrity post | One post object read by millions | Post cache with replicas and local caches; CDN for media |
Ranking service down | No relevance ordering | Circuit breaker; chronological fallback |
Post cache cold after a restart | Hydration hits the database | Request coalescing, warm the most popular posts, load shedding |
Stream outage | New posts not fanned out | Outbox keeps events; fan-out catches up; authors still see their own posts |
Deleted post still in feeds | Could show removed content | Hydration filters deleted posts on every read |
10. Consistency
#- Followers' feeds: eventually consistent; a post appears within seconds (fan-out lag).
- The author's own feed: read-your-writes, synchronously updated.
- Counts: eventually consistent, updated asynchronously.
- Privacy, blocks and deletion: enforced at read time, so effectively immediate even though feed lists are stale.
- Pagination: stable within a session through the ranked snapshot or cursor.
11. Security
#- Visibility checks at hydration for private accounts, followers-only posts and blocked users (object-level authorisation, article 28).
- Spam and abuse: rate-limit posting and following (mass-follow bots), detect spam accounts, and down-rank or remove harmful content.
- Scraping: rate-limit feed reads per user and IP, cap page sizes and pagination depth.
- No leakage through counts or ids: do not reveal private accounts' posts through counts or error messages.
12. Observability
#Signal | Why |
|---|---|
Feed latency p50 and p99, by stage (read feed, merge, rank, hydrate) | The main SLO and where time goes |
Fan-out lag (post created to inserted in feeds), p95 | The freshness SLO |
Fan-out insert rate and worker backlog | Capacity |
Hydration cache hit ratios and filtered-item rate | Cache health; sudden filtering spikes may indicate bugs |
Ranking latency and fallback rate | Ranking health |
Rebuild-on-read rate | Inactive users returning, or feed store loss |
Engagement metrics (scroll depth, likes per session) | Product health; ranking quality |
13. Trade-offs
#Decision | Chosen | Alternative | Why |
|---|---|---|---|
Feed assembly | Hybrid: push for normal authors, pull for celebrities | Pure push or pure pull | Fast reads without celebrity fan-out storms |
Push targets | Active followers only | All followers | Avoid wasted work; rebuild on return |
Feed storage | Capped sorted sets of ids, sharded by user | Store full post objects per feed | Small, cheap, always hydrated with current data |
Privacy and deletion | Enforced at hydration | Rewrite feeds on change | Immediate effect without expensive fan-out of removals |
Ranking | Separate service with chronological fallback | Ranking inline, no fallback | Relevance without risking availability |
Pagination | Session snapshot cursor | Offset | Stable infinite scroll |
14. The final interview answer
#"The feed shows posts from accounts a user follows, ranked, with p99 under 300 ms and new posts visible to followers within about ten seconds. For 10 million daily users that's about 3,500 feed reads a second and 70 posts a second at peak, but posts fan out to an average of 200 followers, and some celebrities have millions.
I use a hybrid model. When a normal author posts, the post service writes the post and an outbox event; fan-out workers insert the post id into each active follower's feed, a capped sorted set of ids in a sharded Redis cluster. Celebrity posts are not pushed; their recent posts are cached once and merged at read time. Inactive users get their feed rebuilt on demand.
A feed read takes the pushed ids, merges celebrity posts, ranks a few hundred candidates with a ranking service that falls back to chronological order, and hydrates the page from post, user and count caches, filtering deleted posts and anything the viewer isn't allowed to see. Authors see their own posts immediately; everything else is eventually consistent. The design scales by sharding feeds by user, scaling fan-out workers on stream lag, and tuning the celebrity threshold by measured cost."
Exercises
#Exercise 1
Fan-out arithmetic
#In one day, 1 million normal authors each post once, with an average of 300 active followers; 2,000 celebrities each post 3 times, with an average of 5 million followers. Compute the daily feed insertions under pure push, and under the hybrid model. Then estimate the extra read-time work the hybrid adds if the average user follows 4 celebrities and reads the feed 12 times a day (100 million DAU).
Exercise 2: Unfollow
#A user unfollows an account. Explain what should happen immediately, what can happen later, and why you would not delete every item from that account in the user's feed synchronously.
Exercise 3: Ranking outage
#The ranking service's p99 latency rises from 40 ms to 900 ms. What happens to feed latency in this design, and what should the feed service do automatically?
Exercise 4: Size the feed store
#At social-media scale (500 million active users), you decide to keep only 300 ids per user in memory, each entry costing 16 bytes in practice (id plus score), with a structure overhead of 1.5 times. How much memory is needed, and how many 64 GB nodes (plus one replica each)?
Show solutionHide solution
Pure push:
Normal: 1,000,000 posts x 300 = 300 millionCelebrities: 2,000 x 3 posts x 5,000,000 = 30 billionTotal: about 30.3 billion insertions/day (about 350,000/s on average, bursty)The celebrities create 99% of the work.
Hybrid: only normal authors are pushed: 300 million insertions/day (about 3,500/s on average), a hundredfold reduction.
Extra read-time work in the hybrid: each feed read fetches recent posts for the 4 celebrities the user follows from the celebrity timeline cache: 100 million DAU x 12 reads x 4 = 4.8 billion cache reads/day, about 56,000/s on average. But they are reads of a small, hot set (2,000 celebrities' timelines), served from cache (and in-process caches), which is far cheaper than 30 billion writes.
Exercise 2
Show solutionHide solution
Immediately: remove the follow relationship (so no new posts from that account are pushed), and make the feed read path filter items whose author is no longer followed (hydration can check the follow relationship for the handful of authors on the page, or keep a small "recently unfollowed" set per user for a few days).
Later: an asynchronous job removes that author's post ids from the user's feed store, or simply lets them age out as new items are added and the feed is trimmed.
Why not synchronously: the feed may contain many items from that author, removing them takes multiple operations on the feed store, and doing it inline would make unfollow slow and fragile. Read-time filtering gives the correct experience immediately at negligible cost, and cleanup can be lazy.
Exercise 3
Show solutionHide solution
Without protection, every feed request waits up to 900 ms for ranking (or for its own timeout), so feed p99 jumps far above 300 ms, threads fill up (Little's Law), and the feed service may cascade into failure (article 23).
Automatic behaviour: the ranking call has a timeout of about 50 ms; on timeout, the feed uses chronological order for that request. A circuit breaker opens when timeouts exceed a threshold, so subsequent requests skip ranking entirely for a while and serve chronological feeds instantly; half-open probes check for recovery. A bulkhead caps concurrent ranking calls. The ranking fallback rate is alerted on, and users see a slightly less relevant but fast feed.
Exercise 4
Show solutionHide solution
Raw: 500 million x 300 x 16 bytes = 2.4 x 10^12 bytes = 2.4 TBWith 1.5x overhead: 3.6 TBNodes: 3.6 TB / 64 GB = about 57 primaries; with one replica each, about 114 nodesAdd headroom (growth, uneven distribution, memory for operations), so perhaps 64 to 70 primaries. This is a significant fleet; alternatives worth discussing are keeping fewer ids in memory (for example 200, with older pages served by fan-out on read), keeping feeds only for users active in the last 7 days, or storing feeds in a disk-backed wide-column store with a cache for the first pages.
Where to go next
#- Next: Design Search Autocomplete (Typeahead), another read path that depends on precomputation.
- Related: the event-driven read models of article 27 and the caching patterns of article 09 underpin this design.
Sources & further reading
- Technology
- Software Engineering
- #caching
- #case study
- #distributed systems
- #roadmap
- #scalability
- #system design
- #system design interview
Connected lessons
Linked from 1 guide
Other pages in the library that point here.
Keep reading
More in Technology →Guide · Technology
Start Here: Your Roadmap from Zero to Job-Ready DSA
Guide · Technology
Heaps and Priority Queues
Guide · Career
A LinkedIn Profile That Gets Recruiter Messages

