Fan-Out Models for a News Feed System: Push vs Pull vs Hybrid

Fan-out models for a news feed system include three primary approaches: Fan-out on Write (push), Fan-out on Read (pull), and a Hybrid strategy that combines both to balance latency and scalability.

When a user publishes content in a social network, the system must distribute that post to all followers' feeds—a challenge known as the fan-out problem. According to the liquidslr/system-design-notes repository, selecting the appropriate fan-out model is critical for maintaining low latency while managing infrastructure costs. The three primary fan-out models each offer distinct trade-offs between write amplification, read performance, and real-time delivery guarantees.

Fan-Out on Write (Push Model)

In the Fan-out on Write approach, also known as the push model, the system immediately propagates a new post to all followers when the author publishes content. As documented in 11. News Feed System/Readme.md, this implementation relies on a dedicated Fanout Service that orchestrates the distribution pipeline.

Implementation Workflow

The push workflow follows four distinct steps. First, the service retrieves the author's friend list from the graph database. Second, it applies filtering logic to respect user preferences such as muted accounts. Third, it enqueues update tasks to a message queue for each follower. Finally, background workers dequeue these messages and populate individual news-feed caches with <post_id, user_id> entries.

def publish_post(user_id, content):
    post_id = store_post(user_id, content)          # Persist the post

    friends = graph_db.get_friends(user_id)         # 1️⃣ Fetch Friend IDs

    filtered = filter_muted(friends, user_id)       # 2️⃣ Apply user settings

    for friend_id in filtered:
        queue.enqueue({
            "feed_user": friend_id,
            "post_id": post_id
        })                                            # 3️⃣ Send to Message Queue
def fanout_worker():
    msg = queue.dequeue()
    feed_key = f"feed:{msg['feed_user']}"
    cache.lpush(feed_key, msg['post_id'])           # 4️⃣ Append post ID to cache

    cache.ltrim(feed_key, 0, MAX_FEED_SIZE)        # Keep only recent N posts

Trade-offs of the Push Model

Fan-out on Write delivers real-time feed updates with minimal read latency, as fetching a feed requires only a simple cache lookup. However, this approach creates write amplification for users with massive follower counts, potentially overwhelming message queues and cache systems during viral post events.

Fan-Out on Read (Pull Model)

The Fan-out on Read strategy, or pull model, stores each post exactly once in a central Post Store. When a follower requests their feed, the News Feed Service aggregates recent posts by querying the author's timeline and merging results on-the-fly.

This approach eliminates write amplification but shifts computational overhead to the read path. Each feed request requires multiple lookups across friend lists and post stores, followed by sorting and ranking operations before returning results.

def get_feed(user_id, limit=20):
    friends = graph_db.get_friends(user_id)         # Retrieve friend list

    post_ids = []
    for friend_id in friends:
        recent = cache.lrange(f"feed:{friend_id}", 0, limit)
        post_ids.extend(recent)                     # Collect recent post IDs

    post_ids = sorted(post_ids, reverse=True)[:limit]
    posts = db.batch_get_posts(post_ids)            # Fetch full post data

    return posts

When to Use the Pull Model

Fan-out on Read scales efficiently for high-profile accounts with millions of followers, as publication generates constant write operations regardless of audience size. However, the increased database load and higher latency during feed generation make this approach unsuitable for real-time applications.

Hybrid Fan-Out Strategy

Production systems often implement a Hybrid approach that dynamically selects between push and pull based on follower count. Regular users with modest networks receive pushed updates for immediate visibility, while celebrity accounts trigger pull-based aggregation to prevent system overload.

The implementation requires maintaining two code paths and classification logic to determine which users qualify for push distribution. When a follower's cache is cold or stale, the system may also fall back to pull-based reconstruction.

def publish_post(user_id, content):
    post_id = store_post(user_id, content)
    if is_celebrity(user_id):
        # Skip push; followers will pull this later

        return
    # Otherwise push as in the first example

    friends = graph_db.get_friends(user_id)
    for friend_id in friends:
        queue.enqueue({"feed_user": friend_id, "post_id": post_id})

Selecting the Appropriate Model

Choosing between fan-out models for a news feed system depends on four critical factors:

  • Follower distribution: Most platforms exhibit power-law distributions where few users have millions of followers while the majority have modest networks
  • Latency requirements: Real-time applications favor push for instantaneous delivery
  • Infrastructure constraints: Write-heavy workloads may necessitate pull for high-fan-out users to prevent message queue saturation
  • Cost considerations: Push consumes more cache memory and network bandwidth, while pull demands greater database CPU during peak read periods

Summary

  • Fan-out on Write provides real-time updates and fast reads but suffers from write amplification for popular users with massive follower counts
  • Fan-out on Read offers constant write costs and scales efficiently for celebrities but increases read latency and database load during feed generation
  • Hybrid models balance performance by pushing to normal users and pulling from high-profile accounts, though they add implementation complexity and require user classification logic
  • The liquidslr/system-design-notes repository demonstrates these patterns in 11. News Feed System/Readme.md with accompanying architecture diagrams showing the Fanout Service workflow

Frequently Asked Questions

What is the main disadvantage of Fan-out on Write for celebrity users?

Fan-out on Write creates massive write amplification when publishing to millions of followers, potentially overwhelming message queues and cache systems. A single celebrity post could generate millions of enqueue operations and cache writes, causing system instability during viral events.

How does Fan-out on Read handle feed latency?

Fan-out on Read increases latency because the system must query multiple sources, aggregate post IDs, sort them chronologically, and fetch full content during each request. This on-the-fly construction makes it unsuitable for real-time applications but ideal for reducing write overhead.

When should a news feed system use the Hybrid model?

A Hybrid approach works best when the user base follows a power-law distribution with many low-follower accounts and few high-follower celebrities. It provides real-time experiences for regular users while protecting infrastructure from the massive fan-out bursts associated with popular accounts.

What role does the Fanout Service play in push-based architectures?

The Fanout Service orchestrates the push workflow by retrieving friend lists, applying content filters, enqueuing updates to distributed workers, and managing the news-feed cache population. According to the source repository, this service is the critical component separating write-time distribution logic from the main application path.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →