Every social product eventually has to answer the same question: when someone posts, who does the work of getting that post into their followers' feeds?

There are two honest answers, and each one breaks in a different place.

Push: fan-out on write

When a user posts, a background worker inserts the post id into every follower's precomputed feed, usually a capped sorted set in a cache.

  • Reads are trivial. Opening the app is one cache lookup.
  • Writes are proportional to followers. A user with 300 followers costs 300 inserts. A user with 50 million costs 50 million.

Pull: fan-out on read

Store each post once. When a user opens the feed, fetch recent posts from everyone they follow and merge them.

  • Writes are trivial. One insert per post.
  • Reads are proportional to followees. Following 2,000 accounts means 2,000 lookups on every refresh.

The numbers decide

Account type Followers Push cost per post Pull cost per reader
Typical user 200 200 inserts small
Popular creator 200K 200K inserts small
Celebrity 50M 50M inserts, minutes of lag one extra lookup

Push is clearly right for typical users and clearly wrong for celebrities. That asymmetry is the whole design.

The hybrid

  1. Mark accounts above a follower threshold (say 100K) as celebrities.
  2. Fan out posts from everyone else on write.
  3. At read time, take the precomputed feed and merge in recent posts from the few celebrities this user follows.
  4. Rank the merged candidates and hydrate the top results from cache.
async function readFeed(userId: string) {
  const pushed = await cache.recentFeed(userId, 200);
  const celebs = await graph.celebritiesFollowedBy(userId);
  const pulled = (await Promise.all(celebs.map((c) => posts.recent(c, 20)))).flat();
  return rank(userId, dedupe([...pushed, ...pulled])).slice(0, 20);
}

Most users follow only a handful of celebrities, so the read-time merge stays cheap.

Details interviewers love

Inactive users

Skip fan-out for users who have not opened the app in weeks, and rebuild their feed on their next visit. This can cut write volume dramatically.

Deletes and privacy changes

A deleted post may still sit in millions of feed caches. Filter at hydration time instead of trying to remove it everywhere.

Ranking changes the storage question

With a ranked feed, the precomputed list is a candidate pool, not the final order. Keep it large enough for the ranker to have real choices.

The takeaway

Neither push nor pull is correct on its own. The right design looks at the distribution of followers, pays the write cost where it is small, and pays the read cost where writes would explode.

For the full walkthrough with estimates and code, see the Design Instagram guide.