> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# News Feed Where the Design Breaks

> Comparing pull versus push feed designs, recommending fan-out-on-write to precompute timelines for low-latency reads while discussing tradeoffs and hybrid strategies for large follower counts.

Now we move to the next step: a high-level design of the system.

So far, we know the user's mobile app talks to our servers with two API calls, and our data lives in three tables in the database. The question is: when Alan opens the app, how do we actually build his feed?

At the simplest level we have a pull-based design: the feed is built when the user requests it.

```http theme={null}
POST /create-post
GET /get-feed
```

Pull-based (fan-out-on-read) — simple workflow

1. Alan opens the app and the app calls the `GET /get-feed` endpoint.
2. The server reads the `follows` table to determine who Alan follows. The query returns 300 accounts.
3. The server queries the `posts` table for recent posts by those 300 accounts (one lookup per account, or equivalent aggregated query).
4. The server gathers a few hundred posts in memory, sorts them by timestamp, keeps the newest 50, and returns those 50 posts to Alan's app.

This approach is functionally correct and simple to implement, but it has scaling and latency issues. Every time a user opens their feed we:

* Read the `follows` table (one read per feed open).
* Perform many lookups to retrieve posts for each followed account (in this example \~300 lookups per feed open).
* Sort and truncate results in memory on each request.

Operational cost example

| Metric | Per-second load (baseline: 600 feed opens/sec) | Peak (5× baseline) |
| - | - | - |
| Reads of `follows` table | 600 reads/sec | 3,000 reads/sec |
| Post lookups (600 × 300) | 180,000 lookups/sec | 900,000 lookups/sec |

If we receive 600 feed opens per second, that becomes:

* 600 reads of the `follows` table per second, and
* 600 × 300 = 180,000 post lookups per second.

If peak traffic is 5× the baseline, this becomes 900,000 lookups per second — a load that will slow the database and break our latency goal (we promised the feed should load within one second).

Most of that work is wasted. For example, Alan may open the feed in the morning, skim some posts, close the app, and reopen it seconds later. Very little will have changed in his feed, yet we rebuild it entirely from scratch.

You might think read replicas fix this, but they only replicate the same wasteful queries across more machines. What we need is a different approach.

Pause and think: every feed is rebuilt from scratch on read. Is there a way to avoid rebuilding?

Yes. Instead of building the feed when Alan reads it, we should build and maintain Alan’s feed ahead of time and store it. When someone John posts, we update Alan’s stored feed (if Alan follows John). In other words, change the feed only when new posts arrive from followed users.

This is the fan-out-on-write approach: when a new post is created, the system pushes that post into the precomputed feed timelines of all followers. Then `GET /get-feed` simply reads Alan’s stored feed (fast, single read) and returns the precomputed list.

```http theme={null}
POST /create-post
GET /get-feed
users
follows
posts
```

<Callout icon="lightbulb" color="#1CB2FE">
  The push (fan-out-on-write) approach trades increased write work and storage for much cheaper, predictable reads and lower read latency. Precomputing timelines is ideal when reads far outnumber writes, because it eliminates per-read aggregation and sorting.
</Callout>

Comparing approaches

| Approach | Read cost | Write cost | Storage | When to use |
| -: | :-: | :-: | :-: | :- |
| Fan-out-on-read (pull) | High — rebuilds feed on each read | Low | Minimal | Small scale, simple implementation, low read traffic |
| Fan-out-on-write (push) | Low — single read of precomputed timeline | High — push to many followers | Higher — per-follower timelines | High read volume, predictable low-latency reads |

<Callout icon="warning" color="#FF6B6B">
  Fan-out-on-write can cause write amplification for very large accounts (e.g., celebrities with millions of followers). For such cases, consider hybrid strategies: lazy fan-out (mix of push + on-read for large fans), per-actor sharding, caching layers (CDN or in-memory caches), or using separate “fanout” queues and background workers to smooth spikes.
</Callout>

Key takeaways and next steps

* For most social feeds at scale, precomputing timelines (fan-out-on-write) provides predictable low-latency reads and much less load on the read path.
* Carefully evaluate tradeoffs: increased write work, storage, and operational complexity versus the benefits on the read path.
* For extremely large follower graphs adopt hybrid patterns and use batching, background workers, and rate limiting to control write amplification.

Links and references

* [Kubernetes Basics](https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/)
* [Designing Data-Intensive Applications — Feed Systems (concepts)](https://dataintensive.net/)
* \[Fan-out patterns and considerations — blog posts and case studies]

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/system-design-for-interview-prep/module/36e67187-d5c7-44a8-9c92-65e2548b2f80/lesson/08ead8bc-e222-4c07-b982-12bc6e0cd31a" />
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.