News feed system design
Scalable news feed design: Fanout, ranking, tradeoffs
Every social media app makes a news feed look effortless. You open the app, refresh the page, and within a fraction of a second hundreds of new posts appear in an order that feels surprisingly relevant. Behind that seemingly simple experience is one of the most demanding distributed systems engineers build.
A News Feed system design has to absorb massive write spikes, serve millions of low-latency read requests, rank content in real time, and remain responsive even when a single post suddenly reaches millions of users. Those competing requirements make it a classic System Design interview problem because every architectural decision introduces tradeoffs between latency, scalability, consistency, storage, and cost.
In this guide, you’ll build a News Feed system from the ground up, explore the major architectural decisions, and understand why large-scale platforms rely on hybrid fanout strategies, multi-layer caching, and carefully defined consistency contracts to keep feeds fast and reliable.
News Feed Design Problem Framing And Baseline Architecture
A news feed breaks first at the tails, not the averages. A single celebrity post can create a write storm that saturates the systems that copy the post into follower feeds, and the visible symptom is usually read p99 blowing past a target like 200 ms because caches miss and storage queues back up.
That failure mode matters because it pins down the shape of the problem. One action produces many downstream writes, while the product requirement is that reads stay fast and stable even when writes spike.
Baseline two-path architecture
A baseline design splits cleanly into a write path that ingests and distributes new posts, and a read path that serves a ranked slice of a user’s feed with aggressive caching. The split exists because the system can spend more work per post asynchronously than it can spend per feed read synchronously.
Use the diagram to trace the write boundary versus the read boundary across the components.
In this baseline, the post enters the post service, the follower set comes from the graph store, and a fanout pipeline materializes candidate feed items for many users. Reads hit the feed service, which prefers caches for speed and falls back to the post store when it needs post bodies or cache misses force a slower path.
Rule of thumb
Protect read p99p99 by moving work off the read path even if it increases background write load.
Tradeoff vocabulary tied to paths
The terms below are only useful when they point to a specific pressure on either the read path, the write path, or both. Without that mapping, teams optimize the wrong subsystem and chase the wrong metric.
Use the mapping widget to connect each term to the path it stresses and the metric that exposes it.
Read amplification increases work per feed request, often visible in higher
feed serviceQPS to caches and storage and worse read p99p99.Write amplification increases work per post, often visible in higher background queue depth, larger fanout batches, and spillover retries.
Freshness lag shows up when the pipeline cannot keep up, so recent posts arrive late in materialized feeds.
Cache hit rate determines whether the read path stays in memory or falls into storage, which changes both latency and backend load.
Tail latency is driven by the slowest dependencies on the read path, so a small miss rate can dominate p99p99 even when averages look fine.
Questions that drive architecture choices
Once the baseline split is clear, the design questions become concrete because each answer moves load across the write and read paths. Materializing feed items early reduces synchronous read work but increases fanout load and storage writes, while materializing late makes reads heavier and more sensitive to cache misses.
The hard decisions usually cluster around three questions. Where to materialize the feed, per user inbox versus computed on read. How ranking is applied, precomputed during fanout or computed during read with fresher features. What consistency users notice, because the acceptable mismatch between graph updates, post visibility, and ranking determines whether the pipeline can be asynchronous without breaking the product contract.
Fanout Strategies And Feed Storage Mechanics
A feed system fails in different places depending on when it does the work. Fanout at write time pushes compute and storage into the publish path, while fanout at read time pushes compute into the request path. Because follower graphs are power law, one account can shift load by orders of magnitude, so a single strategy rarely holds across the whole graph.
Push, pull, and hybrid fanout failure points
The core decision is where the system pays the join between authors and followers. With push fanout, a publish event writes into many per-user inbox timelines, so read latency stays predictable but write amplification can saturate storage and queues when an author has many followers.
To make the tradeoffs concrete, compare the strategies across latency, write QPS, storage, and worst-case failure.
With pull fanout, the publish path stays cheap because posts land once in an author outbox, but reads must query many outboxes and merge them, so tail latency rises with the number of followed accounts and with cache misses. Hybrid fanout absorbs the power law by pushing for typical authors and switching large authors to pull, which caps write amplification while keeping most reads fast.
Inbox and outbox storage mechanics
Once the strategy is chosen per author segment, the next constraint is how timelines fit in memory. A common inbox representation is a Redis ZSET keyed per user, with score set to the event timestamp and the member containing a post id and maybe an author id.
The widget shows a ZSET timeline where inserts are followed by trim-to-800 and reads take the top-100.
Insertion uses ZADD to add the new post, then trimming uses ZREMRANGEBYRANK to evict older ranks so the key stops growing. Reads use ZREVRANGE to fetch the most recent items, and the cap prevents a long-inactive user from accumulating unbounded memory. Eviction has a product effect because if a user scrolls deep, older items may be missing and must be reconstructed by falling back to pull from outboxes or by storing older pages in a colder store.
Eviction rule
Cap inbox keys by count, not time, so a burst does not create an unbounded key even if timestamps are close.
Hybrid read path merge under a latency budget
Hybrid systems still need a deterministic read plan because every extra fetch adds tail latency. The read path typically starts with the user inbox as the fast lane, then adds candidates from celebrity outboxes only when the user follows those authors.
The sequence diagram shows how FeedSvc merges inbox items with celebrity outboxes and hands candidates to a ranker.
FeedSvc first fetches the top slice from RedisInbox, then calls GraphSvc to find which followed authors are in the celebrity segment. For those authors, it fetches recent items from CelebrityOutbox and merges by timestamp before sending a bounded candidate set to Ranker. The merge is bounded to keep p99p99 stable, which means the system may under-fetch from outboxes and rely on ranking to select the best items from a limited window.
Tuning the blast radius
The celebrity threshold is a control knob that trades write amplification against read latency. Set it too low and many authors flip to pull, increasing merge cost and cache pressure at read time. Set it too high and a small set of large authors can overload the publish pipeline.
Ranking, Caching, And Consistency Contracts
Candidate generation and ranking sit on the hot path because the client is waiting on the ordered feed, not just a set of IDs. If candidate generation returns quickly but the ranker stalls, the system still misses the end to end latency budget, so the design has to treat ranking as part of the request lifecycle rather than an offline afterthought.
A practical funnel keeps each stage small enough that the next stage can execute within its CPU and RPC budget. The usual shape is wide retrieval that tolerates approximate recall, followed by progressively heavier scoring on fewer items so the highest cost models only run on what might realistically land on screen.
The key constraint is that the final stage latency is bounded by both model cost per item and item count, so reducing from 100 to 30 items can be the difference between a synchronous score and a fallback. When the budget cannot hold, systems degrade by skipping features, using a smaller model, or returning a partially ranked list and filling in with background refresh, but each fallback changes what users see and must be deliberate.
Cache layers that match access patterns
Caching works when the key matches the dominant read pattern and invalidation matches the dominant write pattern. A feed cache keyed by (viewer_id,cursor) can return a ready to render list quickly, while a post cache keyed by post_id avoids recomputing hydration fields for every feed impression, and a celebrity cache reduces repeated fanout work for accounts whose posts appear in many feeds.
Delete and edit flows are where cache choices become visible because they force invalidation across layers. Typical handling splits by blast radius.
For
delete, tombstone thepost_idin the post cache and filter it during hydration, then lazily rebuild viewer feed caches as they expire.For
edit, version the post content and let hydration read the latest version, while feed caches store only stable identifiers plus lightweight ranking metadata.For cold start rebuild, backfill from persistent storage into the feed cache asynchronously, but serve a smaller initial page using on demand candidate generation so first paint does not block on full rebuild.
Invalidation rule If a cache entry cannot be invalidated within the write path budget, store references not copies, and fix up at read time.
Consistency contracts users actually notice
A feed is rarely strictly consistent, but the user experience depends on which reads must reflect which writes. Authors notice read your writes because they post and immediately refresh their own profile or feed, while followers tolerate eventual delivery because fanout and ranking can take seconds, especially under load.
Pagination adds a separate contract because cursors define what repeats or disappears across pages. If ranking features change between page fetches, the same item can move across the boundary and show up twice or be skipped, so stable pagination usually pins to a snapshot. Common patterns are to include a ranking version in the cursor, or to paginate on a stable key like (rank_bucket,post_id) and accept that freshness changes only apply after a refresh.
Wrap up with interview level decisions
A strong answer ties ranking, caching, and consistency to explicit assumptions about latency and correctness, then states what breaks first. The fastest design usually caches hydrated posts and short feed pages, runs a bounded ranker synchronously, and uses eventual fanout for followers while preserving read your writes for authors via client side optimistic inject plus server reconciliation.
Assumptions that force redesign include strict no duplicates pagination, instant delete everywhere, or requiring heavy models on every request. When one of those constraints appears, the system typically shifts toward snapshotting, stronger invalidation, or precomputation, and each shift trades freshness or cost for a clearer contract.










