In this article
  1. Before you start
  2. Why interviewers ask this
  3. News feed and social graph from first principles
  4. Worked example
  5. Trade-offs and edge cases
  6. How to answer it in an interview
  7. Common mistakes
  8. Follow-up questions
  9. Sources

Before you start

This page belongs to the distributed systems interview guide and assumes you can do a quick size estimate; the back-of-the-envelope estimation page teaches it.

Why interviewers ask this

The question tests whether a candidate can turn one vague product sentence into numbers, a data model and a defensible trade-off. Candidates report variants such as a Twitter-like service, an Instagram feed, a friends activity feed and a Facebook-like platform that shows friend counts, and a first-, second- or third-level connection badge.

A weak answer draws boxes labeled "feed service" and "database" and stops. A strong answer separates the two problems: the graph (who follows whom, read constantly) and the feed (what each person sees, built from posts). It states the read-to-write ratio, picks when to build feeds, and says what happens for an account with a huge audience. A Staff-level answer also names what is allowed to be stale, because the product tolerates a short delay in a feed but not a lost post.

News feed and social graph from first principles

Social graph
A social graph is a data model of people and other objects, called nodes, joined by typed, directed links, called edges, such as follows, friends, likes and comments, that lets a service ask who is connected to whom.
News feed
A news feed is a per-user, time-ordered list of recent posts from the accounts that user follows, assembled by the service so a person can open one screen instead of visiting every profile.

In plain words

Think of a newspaper stand. You can pre-assemble a bundle for every reader each time a story is printed. Or you can wait for the reader and gather stories from each publisher they like. Bundling ahead makes pickup quick but needs much copying. Gathering on arrival saves copying but makes each pickup slow. The analogy breaks in one place: a stand has a fixed number of readers, while a feed service has accounts whose follower counts differ by millions.

In one precise sentence, the design stores edges once and posts once. Then it either precomputes each feed (fan-out on write) or computes it at read time (fan-out on read).

Step 1: Model the graph and the posts

Store two things separately. The graph is a set of typed objects and typed, directed edges. Bronson et al. (2013) describe Facebook's version this way and note that an association is often paired with an inverse edge, so a friend link exists in both directions. A follow link is one directed edge; a friend link is two.

A post is one row: an id, an author, a time and a body. Index follow edges both ways, because feed building needs "who follows author X" (followers) and the follow list of a reader needs "whom does user Y follow". Input: a follow action or a new post. Output: one or two edge rows, or one post row. Nothing about feeds exists yet; you have only the raw facts a feed is built from.

Step 2: Build the feed by fan-out on write, fan-out on read or both

Fan-out on write copies the id of each new post into the cached feed list of every follower, so reading a feed is one lookup. Fan-out on read stores nothing per follower: at read time the service fetches the follow list, pulls each followed account's recent posts and merges them by time. Write is cheap and read is expensive in the second design, and the reverse in the first.

The deciding number is the follower count. For ordinary accounts, pushing is fine because a feed is read far more often than a post is written. For an account with tens of millions of followers, one post becomes tens of millions of writes, so the common answer is a hybrid: push for ordinary accounts, and pull the few very large accounts' recent posts at read time. Krikorian's Timelines at Scale talk is described as covering the architecture Twitter used for thousands of events a second. Where to draw the line is a tunable threshold, not a fixed constant.

The hybrid pushes ordinary accounts and pulls very large onesTable comparing fan-out on write, fan-out on read and a hybrid by where the work happens, read cost, write cost and how a post from a huge account is handled.QuestionFan-out onwriteFan-out onreadHybridWork happenswhenpostingwhenreadingboth, splitby sizeRead costone listlookupmanylookups,mergelist plus fewpullsWrite costone writeper followerone writecapped forbig accountsHuge-accountpostslowdeliveryno specialcostpulled atread timeDiagram: Interview Clozo, CC BY 4.0 ·interview.clozo.ai/blog/design-a-news-feed-and-a-social-graph.html
The hybrid pushes ordinary accounts and pulls the few accounts with huge follower counts.CC BY 4.0 — source: How do you design a news feed and a social graph?
Text description of the diagram
  • Fan-out on write does its work when a post is written.
  • Fan-out on read does its work when the feed is opened.
  • A hybrid pulls the recent posts of very large accounts at read time.

Step 3: Serve the feed from a cached list and a cursor

The read path fetches the reader's cached feed list, a short list of post ids, looks up the post bodies, and returns one page. Keep only a bounded number of ids per user, because few people scroll far. If the feed list is missing (a new user, an evicted cache entry), rebuild it with the fan-out-on-read method and store the result.

Page with a cursor, not an offset. A cursor is the id or timestamp of the last item the client saw, so "next page" means "posts older than this". An offset page shifts whenever a new post arrives at the top, so a reader would see duplicates. Bronson et al. (2013) describe the same idea for the graph: lists are kept by time and a read asks for the most recent slice. For ranking, the simplest answer is time order; a ranked feed adds a scoring step before returning the page. The application programming interface (API) design page covers cursor pagination.

Step 4: Scale the graph with shards, a cache and one leader per shard

The graph is read-heavy. In Facebook's trace, 99.8% of requests were reads and 0.2% were writes, a ratio of about 499 to 1 (computed from those two figures).1 So the design optimizes reads: shard the data by a key so no server holds it all, and put caches in front of the database.

The same paper reports that Facebook's web servers originally read MySQL directly with memcache as a lookaside cache, and that the graph store replaced this for the data types that fit its model. Each shard has one leader and every write for that shard goes through it, so writes are consistent. Followers (cache servers) receive updates asynchronously, which is called eventual consistency: replicas agree after a short delay. The paper measured replica lag under 1 second 85% of the time and under 10 seconds 99.8% of the time. The cache layer itself is described in Scaling Memcache at Facebook.

Posts are fanned out to cached feeds in front of a sharded graphFlow of a feed system: posts and follow edges are stored once, fan-out workers copy each post id to follower feeds, a feed cache serves reads, and a sharded graph cache sits in front of the graph.Post storeone row perpostFollow graphdirected edgesFan-outworkerspush orpullFeedcachepost idsper usercachedShardedgraph cacheleader andfollowersDiagram: Interview Clozo, CC BY 4.0 ·interview.clozo.ai/blog/design-a-news-feed-and-a-social-graph.html

Posts are stored once, fanned out to follower feeds, and read from one cached list per user.CC BY 4.0 — source: How do you design a news feed and a social graph?
Step-by-step description
  1. Posts and follow edges are stored separately.
  2. Workers copy each post id to followers.
  3. A read is one cached list.
  4. Shards and caches serve the read-heavy graph.
  • Posts and follow edges are stored once.
  • Fan-out workers copy each post id into the feed cache of every follower.
  • The feed cache serves each read from one list.
  • The graph is sharded and cached in front of the database.

Knowing it is half the job. Saying it is the other half.

Interview Clozo is an AI interview copilot for real interview rounds: it hears the question and puts a strong answer on your screen, and you say it in your own words. See the features or how it works.

Start Free Trial →

Worked example

The inputs are assumptions, not measurements: 100 million daily active users, 2 posts per user per day, 200 followers and 200 followed accounts per user on average, 10 feed opens per user per day, 800 post ids kept per feed at 8 bytes each (all illustrative).1

Fan-out on write turns 200 million posts a day into 40 billion feed-list writes a day, about 462,963 a second, which is 40 writes for every feed read. Fan-out on read turns 1 billion feed opens into 200 billion follow-list lookups a day, about 2,314,815 a second. Feed reads are about 11.6 thousand a second (11,574.1 on average). The feed lists take 6,400 bytes per user, 640 gigabytes in total, or 1,920 gigabytes with three replicas.1

With these illustrative inputs, fan-out on read does about five times the work of fan-out on write, and one 50-million-follower post needs 41.7 minutes to deliver at 20,000 writes a second.
Quantity (illustrative inputs)Value
Posts per day200,000,000
Feed reads per day1,000,000,000
Feed reads per second, average11,574.1
Fan-out on write: feed-list writes per day40,000,000,000
Fan-out on write: writes per second462,963
Fan-out on read: lookups per day200,000,000,000
Fan-out on read: lookups per second2,314,815
One feed list (800 ids, 8 bytes each)6,400 bytes
All feed lists, one copy640 gigabytes
One post from a 50-million-follower account at 20,000 writes a second2,500 seconds (41.7 minutes)

The last row is why the hybrid exists: one such post equals 250,000 posts from an ordinary 200-follower account.1 The sizing method is the one in back-of-the-envelope estimation.

Fan-out on read does about five times the work of fan-out on writeBar chart in thousands of operations a second for illustrative inputs: feed reads 11.6, fan-out on write 463 feed-list writes, and fan-out on read 2,315 follow-list lookups.Work per second (thousand/s)05001,0001,5002,0002,500Feed readsPush writesPull lookupsOperation11.64632,315Diagram: Interview Clozo, CC BY 4.0 ·interview.clozo.ai/blog/design-a-news-feed-and-a-social-graph.html
In this illustrative example, fan-out on read costs about five times the work of fan-out on write.CC BY 4.0 — source: How do you design a news feed and a social graph?
Text description of the diagram
  • Feed reads are about 11.6 thousand a second.
  • Fan-out on write needs about 463 thousand feed-list writes a second.
  • Fan-out on read needs about 2,315 thousand follow-list lookups a second.

Trade-offs and edge cases

No fan-out strategy wins every row, so the workload decides. Push gives fast reads and wastes writes on followers who never log in; pull wastes read work on every open; a hybrid needs a threshold and two code paths, and a feed must merge pushed and pulled posts correctly.

Edge cases to name:

  • Celebrity posts. Delivery takes minutes (41.7 in the example above), so pull large accounts at read time instead.
  • Counts. Do not count edges by scanning. Facebook's graph store has a separate count query, and 1% of the counts it returned were 512K or more, so counts are stored and cached.1 A friends-count-for-millions-of-posts question is answered with stored counters.
  • Deletes and unfollows. A deleted post must disappear from copied feed lists; store ids and check the post store when rendering.
  • Staleness. Feeds can lag; read-after-write can break after a failover, so show a user their own new post locally.
  • Graph databases. A social graph does not require one: Facebook served its graph from sharded MySQL with caches and a fixed set of queries, although its interface is graph-shaped (Bronson et al., 2013).

For the chat variant, which needs a live push channel, see designing a chat system.

How to answer it in an interview

Interviewer asks

How would you design a news feed and a social graph?

A strong answer

I model the social graph as users and directed follow edges, sharded by user id with a cache in front, because reads dominate. A post goes to a post store, and fan-out workers push its id into each follower's cached feed list, so reading a feed is one lookup. For accounts with huge follower counts I skip the push and merge their recent posts in when the feed is read. Feeds are eventually consistent, and I page with a cursor, not an offset.

The spoken structure: say the two problems (graph and feed), give the read-to-write numbers, choose push, pull or hybrid with the reason, then name consistency and pagination.

Common mistakes

  • "I'll use fan-out on write for everyone." (wrong) One post from a very large account becomes tens of millions of writes. (right) "Push for ordinary accounts, pull for very large ones, with a threshold I can tune."
  • "The feed needs strong consistency." (wrong) A short delay is acceptable and buys availability. (right) "Writes go through one leader per shard; followers catch up asynchronously."
  • "I'll count friends by counting edges at read time." (wrong) That scans a list that can be huge. (right) "I keep a counter per user and cache it."
  • "Page 2 is offset 20." (wrong) New posts shift offsets and cause duplicates. (right) "The cursor is the last post's time and id."
  • "Start by choosing a database." (wrong) The choice depends on numbers. (right) "First I estimate reads, writes and storage."

Follow-up questions

How would your system function if it had to scale to hundreds of millions or potentially a billion users?

Shard the graph and the feed lists by user id, keep reads in caches with one leader per shard for writes, and add shards as storage grows; Facebook's published system handled a billion reads and millions of writes a second. Re-run the estimate at the new scale and move the push-or-pull threshold.

How would you show whether a profile is a first-, second- or third-level connection?

Compare friend lists from both ends. First level is one edge lookup; second level is an overlap of the two lists. For third level, fetch one list and the other person's two-hop set, up to 40,000 ids (illustrative);1 any overlap means three hops or fewer. Cache the result per pair.

How do you fetch the friends count for millions of posts?

Store a counter per account and update it when edges change, then batch-read counters for the authors on the page. Never count edges at read time.

Do you need a graph database for a social graph?

Not necessarily. Sharded relational storage with a cache and a small set of fixed queries ran Facebook's graph; a graph database is a choice, not a requirement.

How do you paginate a news feed?

Use a cursor, the time and id of the last item seen, and return posts older than it. See also representational state transfer (REST) API interview questions.

Does a news feed need strong consistency?

No. Eventual consistency is the usual choice for reads; make sure the author sees their own post at once by adding it locally.

Key takeaways
  • A social graph is typed nodes and directed edges; reads outnumber writes about 499 to 1 in Facebook's published trace.
  • Fan-out on write precomputes feeds; fan-out on read builds them when opened; a hybrid pulls very large accounts.
  • The follower count decides the strategy, so estimate the numbers before drawing boxes.
  • Serve feeds from a cached id list with cursor pagination; accept eventual consistency.
  • Count stored, not scanned.

Sources

  1. TAO: Facebook's Distributed Data Store for the Social Graph — USENIX ATC 2013 (Bronson et al.), 26 Jun 2013
  2. Timelines at Scale (Raffi Krikorian, QCon San Francisco 2012) — InfoQ, 3 Apr 2013
  3. Scaling Memcache at Facebook — USENIX NSDI 2013 (Nishtala et al.), 2 Apr 2013