Facebook Feed
Design a news feed with ranking, fan-out, and real-time updates for billions of users.
Problem Statement
Design Facebook Feed, the personalized home feed that shows posts from friends, followed pages, groups, recommendations, and ads. The system must ingest new posts and engagement actions, generate relevant candidates, rank them with machine learning, and return a fresh, deduplicated feed page within a tight latency budget.
At interview scale, assume billions of daily active users, hundreds of millions of new posts per day, tens of billions of likes and comments per day, and a read path that is far hotter than the post creation path. The hard part is not storing posts chronologically. The crux is feed ranking: picking candidates from the social graph, hydrating ranking features, scoring them quickly, mixing organic and ads, honoring privacy, and keeping cached ranked post ids fresh.
A strong design uses hybrid fanout. Most ordinary producers push recent post ids into follower feed caches, while high-degree pages, celebrities, and large groups are pulled at read time to avoid enormous fanout storms. Media is stored in an object store and served by CDN, while likes, comments, shares, hides, and seen-state flow through an action store and event pipeline that continuously updates ranking features.
Business use case
The feed is the primary engagement surface for a social network. It keeps users informed about friends, communities, creators, news, entertainment, and commerce while supporting monetization through relevant ads.
For the business, ranking quality directly affects retention, session length, creator distribution, ad revenue, and trust. A feed that is only chronological misses important updates and is easy to spam; a feed that over-ranks stale or low-quality posts loses user confidence.
Functional Requirements
Return a personalized ranked feed page for a user with pagination and refresh support.
Ingest posts from friends, pages, groups, and creators with text and media attachments.
Generate candidates from social graph edges, group membership, followed pages, recommendations, and friend-of-friend signals.
Rank candidates using freshness, affinity, engagement, content quality, viewer preferences, and policy constraints.
Record engagement actions such as likes, comments, shares, reactions, hides, reports, clicks, dwell time, and impressions.
Deduplicate posts across surfaces and avoid showing already seen content repeatedly.
Interleave organic posts and ads while respecting frequency caps and ad relevance.
Serve media through object storage and CDN without putting blobs on the feed API path.
Non-Functional Requirements
Latency
The first feed page should return in about 200ms p99 at the regional service boundary. Allocate roughly 20ms to gateway and auth, 30ms to feed cache lookup, 60ms to candidate and feature hydration, 50ms to ranking and interleaving, and the rest to serialization and network overhead. Scrolling pagination can tolerate slightly higher latency if it is prefetched.
Availability
Feed reads should target 99.99 percent availability or better. If ranking, ads, or engagement aggregation is degraded, the system should fall back to cached ranked post ids, simplified models, or chronological recent posts rather than showing an error.
Read-heavy scalability
Feed reads dominate writes. The design must scale feed cache reads, feature lookups, ranking calls, and media URL hydration independently. Read paths should avoid synchronous fanout, large graph scans, and joins across unbounded tables.
Freshness versus relevance
Users expect recent posts to appear quickly, but the best feed is not purely chronological. The system should update feed caches when friends post, pull very high-degree sources on demand, and let ranking balance recency against predicted engagement, relationship strength, and quality.
Privacy and correctness
Visibility rules are mandatory. A post should never appear to a viewer who is not allowed to see it, even if a stale feed cache contains the post id. The final hydration step must re-check audience, blocks, deletion state, group membership, and policy restrictions.
Ranking quality observability
The system needs online metrics, offline evaluation, A/B tests, feature freshness monitoring, and model version tracking. Ranking regressions can reduce engagement or increase harmful content even when infrastructure metrics look healthy.
Cost efficiency
Scoring every possible post for every request is too expensive. Use hybrid fanout, candidate pruning, cached ranked ids, approximate counters, batched feature computation, and tiered model execution to reserve heavy ranking for the most promising candidates.
Capacity Estimation
Assumptions
Assume 2B daily active users. Each user makes about 20 feed page requests per day across app opens, refreshes, and infinite scroll. Each feed page returns 25 items. The system receives 300M new posts per day, 35 percent of posts include media, and the average media original is 2 MB before derived thumbnails and video renditions.
Assume 95 percent of posts come from ordinary users, pages, or groups that can be pushed to an average of 300 recipient feed caches. The remaining 5 percent are high-degree producers and are pulled at read time. Engagement volume is 20B actions per day. Cache each active user with about 500 ranked post ids, storing 16 bytes per id plus metadata and replication overhead.
Daily active users
2B users
Large social-network scale with global traffic
Feed page reads
40B requests per day
2B users times 20 feed page requests per day
Average feed read QPS
463K requests per second
40B divided by 86,400 seconds
Peak feed read QPS
4.6M requests per second
10x peak over average during regional traffic spikes
New posts
300M posts per day
About 3,500 post writes per second average and 35,000 peak
Push fanout inserts
85B feed-cache inserts per day
95 percent of 300M posts times 300 recipients
Average fanout write QPS
990K inserts per second
85B divided by 86,400 seconds before batching and coalescing
Engagement actions
20B actions per day
Likes, comments, shares, reactions, hides, reports, clicks, and impressions
Hot feed cache footprint
50 to 100 TB
2B users times 500 ids times 16 bytes is 16 TB raw, then metadata and replication
Hot action-store retention
500 TB replicated for 30 days
20B actions per day times 200 bytes times 30 days plus indexes and replicas
Media ingest
210 TB per day raw originals
105M media posts per day times 2 MB, before thumbnails, transcoding, and replicas
Calculations
- Feed reads: 2B users times 20 feed page requests per day is 40B requests per day. 40B divided by 86,400 seconds is about 463K average read QPS. A 10x regional peak gives about 4.6M read QPS.
- Items served: 40B feed pages times 25 items is 1T feed items returned per day. Ranking cannot score the entire universe online for each request, so the system must use candidate pruning and cached ranked post ids.
- Post writes: 300M posts per day divided by 86,400 seconds is about 3,500 average post writes per second. With a 10x peak, plan for about 35,000 post writes per second.
- Hybrid fanout: 95 percent of 300M posts is 285M push-fanout posts. 285M times 300 average recipients is 85.5B feed-cache inserts per day, or about 990K inserts per second average before batching.
- Engagement writes: 20B actions per day divided by 86,400 seconds is about 231K action writes per second average, with multi-million QPS peaks for viral events.
- Feed cache: 2B users times 500 cached post ids times 16 bytes is 16 TB raw ids. Add rank scores, cursors, timestamps, model versions, Redis or key-value overhead, and replication to reserve roughly 50 to 100 TB.
- Action storage: 20B actions per day times 200 bytes is 4 TB raw per day. Thirty days is 120 TB raw; with replicas, indexes, and compaction overhead, plan for about 500 TB of hot action data.
- Media: 35 percent of 300M posts is 105M media posts per day. At 2 MB each, originals require about 210 TB per day before derived formats, thumbnails, CDN cache, and object-store replication.
API Design
/api/v1/feedReturns a personalized ranked feed page for the authenticated viewer. The cursor encodes position, rank version, and freshness watermark rather than exposing raw offsets.
Request
GET /api/v1/feed?limit=25&cursor=rank_57_page_2 Authorization: Bearer viewer_token
Response
{
"items": [
{
"postId": "post_901",
"authorId": "user_42",
"source": "friend",
"rankReason": "close friend and active discussion",
"createdAt": "2026-07-26T06:45:00Z",
"media": [
{ "mediaId": "media_88", "cdnUrl": "https://cdn.example.com/m/media_88.jpg" }
],
"viewerState": { "seen": false, "liked": false }
}
],
"nextCursor": "rank_57_page_3",
"rankVersion": "ranker_v57",
"generatedAt": "2026-07-26T07:10:00Z"
}
200— Ranked feed page returned401— Authentication required429— Client is requesting too aggressively503— Feed unavailable after fallback attempts
/api/v1/postsCreates a post, persists metadata, attaches uploaded media ids, and emits a fanout event. The API does not synchronously update every follower feed cache.
Request
{
"authorId": "user_42",
"audience": "friends",
"text": "Launching the new project today",
"mediaIds": ["media_88"],
"clientMutationId": "client_abc_123"
}
Response
{
"postId": "post_901",
"authorId": "user_42",
"visibility": "friends",
"createdAt": "2026-07-26T06:45:00Z",
"fanoutState": "queued"
}
201— Post created400— Invalid content, audience, or media reference401— Authentication required403— Author is not allowed to post to this audience429— Author or client is rate limited
/api/v1/feed/actionsRecords a viewer action on a feed item. Actions update the durable action log immediately and update counters, ranking features, and notifications asynchronously.
Request
{
"postId": "post_901",
"actionType": "like",
"viewerId": "user_77",
"feedSessionId": "feed_sess_55",
"clientEventTime": "2026-07-26T07:11:03Z"
}
Response
{
"actionId": "act_555",
"postId": "post_901",
"actionType": "like",
"accepted": true
}
202— Action accepted400— Invalid action401— Authentication required403— Viewer cannot interact with this post409— Duplicate idempotent action
/api/v1/feed/seenStores seen-state and impressions so the next feed refresh can deduplicate items and ranking can learn which posts were actually exposed.
Request
{
"feedSessionId": "feed_sess_55",
"seenPostIds": ["post_901", "post_812"],
"lastVisibleAt": "2026-07-26T07:12:10Z"
}
Response
{
"accepted": true,
"dedupeWindowHours": 48
}
202— Seen-state accepted400— Malformed post id list401— Authentication required413— Too many ids in one request
/api/v1/posts/{postId}/commentsReturns the top comments or a paginated comment thread for a post. Comments are not embedded unbounded in feed responses because viral posts can have millions of comments.
Response
{
"postId": "post_901",
"comments": [
{ "commentId": "c_1", "authorId": "user_88", "text": "Congrats", "createdAt": "2026-07-26T07:14:00Z" }
],
"nextCursor": "comments_page_2"
}
200— Comments returned401— Authentication required403— Viewer cannot see this post404— Post not found or deleted
The feed read API should return ranked post envelopes and media URLs, not raw media bytes. Mutation APIs publish events so fanout, notifications, counters, and ranking-feature updates happen asynchronously. The final feed hydration step must still enforce visibility because cached ranked ids can be stale.
Database Design
The logical model separates content, graph, feed cache, and actions. Posts and media are durable content records. The social graph answers who can produce candidates for whom. Feed cache stores precomputed ranked post ids for fast reads. The action store captures every like, comment, share, hide, report, click, dwell event, and impression used by ranking.
At large scale these are not one relational database. They are specialized stores: a graph or TAO-like store for edges, a wide-column or key-value post store, a distributed cache or key-value feed cache, a write-optimized action log, and object storage plus CDN for media.
| source_id | bigint | Viewer, page follower, group member, or friend source |
| target_id | bigint | Friend, page, group, creator, or blocked user |
| edge_type | varchar(32) | Friend, follow, group_member, block, mute, close_friend |
| state | varchar(20) | Active, pending, blocked, muted, or deleted |
| affinity_score | float | Precomputed relationship strength feature |
| updated_at | timestamp | Used for graph freshness and cache invalidation |
| shard_key | bigint | Hash or range shard for adjacency-list storage |
| post_id | bigint | Primary key generated by a distributed id service |
| author_id | bigint | User, page, group, or creator that produced the post |
| author_type | varchar(20) | User, page, group, or recommendation source |
| created_at | timestamp | Primary recency signal and partition dimension |
| audience | varchar(32) | Public, friends, group, custom, or private |
| text_ref | varchar(256) | Inline text or pointer to large content storage |
| media_ids | json | Small ordered list of object-store media ids |
| quality_score | float | Offline or nearline content-quality prior |
| visibility_state | varchar(20) | Active, deleted, demoted, blocked, or under_review |
| user_id | bigint | Partition key for one viewer feed cache |
| rank_version | varchar(32) | Model and policy version used to produce this ordering |
| position | int | Ranked position within the cached window |
| post_id | bigint | Candidate post id, hydrated at read time |
| rank_score | float | Score used for ordering and debugging |
| reason | varchar(64) | Friend activity, group update, page follow, recommendation, or ad slot |
| generated_at | timestamp | Cache freshness watermark |
| expires_at | timestamp | Short TTL to prevent stale feeds from dominating |
| event_id | uuid | Idempotency and dedupe key |
| post_id | bigint | Partition or clustering dimension for post-centric reads |
| actor_id | bigint | User that produced the action |
| action_type | varchar(32) | Like, comment, share, hide, report, click, impression, dwell |
| created_at | timestamp | Event time for time-windowed features |
| parent_comment_id | bigint nullable | Threading for comment replies |
| payload_ref | varchar(256) nullable | Pointer to comment text or larger payload |
| source_surface | varchar(32) | Feed, profile, group, notification, or search |
| media_id | bigint | Primary id referenced by posts |
| owner_id | bigint | Uploader for access checks and deletion |
| object_uri | varchar(512) | Object-store location for the original |
| renditions | json | CDN paths for thumbnails, resized images, or video variants |
| content_hash | varchar(128) | Deduplication and abuse matching |
| moderation_state | varchar(20) | Clean, blocked, pending, or sensitive |
| created_at | timestamp | Upload time |
Indexes
- social_edges.source_id, edge_type supports candidate generation from the viewer outward.
- social_edges.target_id, edge_type supports reverse fanout to followers when a producer posts.
- posts.author_id, created_at supports pulling recent posts from high-degree pages, groups, and creators.
- feed_cache_entries.user_id, position supports fast ordered reads of cached ranked post ids.
- engagement_events.post_id, created_at supports post-centric counters, comment fetches, and ranking features.
- engagement_events.actor_id, created_at supports viewer history, seen-state, and dedupe.
- media_objects.content_hash helps deduplicate uploads and match known-bad media.
Relationships
A feed item references a post id. The post references an author and optional media ids. Social edges define whether the author or container is eligible for a viewer. Engagement events reference both actor and post. The feed serving path should not join these tables directly in a relational sense; it should perform bounded point lookups and batched hydration from stores optimized for each access pattern.
NoSQL alternatives
Use a graph or adjacency-list store for social edges, partitioned by source id and replicated by region. Use a wide-column or key-value store for posts, partitioned by post id with secondary views by author and time. Use Redis, Memcached, or a custom distributed cache for feed_cache_entries, storing compact ranked post-id arrays per user. Use Kafka or Pulsar plus a columnar lake or OLAP store for engagement events, with nearline feature stores for ranking.
Media belongs in object storage, not in the post database. Store originals and renditions in an object store, serve them through CDN, and keep only ids, moderation state, hashes, and URLs in metadata stores.
High-Level Architecture
The read path first tries the ranked feed cache. On a miss or refresh, candidate generation reads the graph, post store, and action signals, then the ranker scores candidates and mixes organic posts with ads. Post creation, impressions, actions, and fanout are asynchronous through the event bus.
The architecture is split around the ranking critical path. The Feed API is stateless and handles authentication, pagination, hydration, visibility checks, and response shaping. The ranked feed cache stores compact post-id windows so the common read path avoids graph expansion and heavy model calls. When cache entries are stale or exhausted, the candidate service rebuilds candidates from pushed feed ids, recent posts from high-degree sources, graph edges, group membership, and recommendations.
Fanout is hybrid. Normal users, small pages, and ordinary groups push new post ids to followers through fanout workers because the recipient set is bounded. Celebrity pages, large public groups, and viral sources are pulled at read time because pushing to tens or hundreds of millions of followers would dominate write capacity and create hot shards.
Ranking and aggregation are distinct. The ranker scores candidates using ML features from the action store, graph store, and post metadata. The aggregator applies business rules: dedupe by post and story, remove seen or hidden items, enforce privacy, apply freshness windows, reserve ad slots, and return media references that clients load through the CDN.
Request Flow
- 1
Feed request enters the platform
The client calls the feed endpoint with an auth token, cursor, device context, and limit. The API gateway authenticates the viewer, applies rate limits, and routes to a regional Feed API instance close to the user.
- 2
Feed API checks ranked feed cache
The Feed API reads the viewer's cached ranked post-id window. If enough fresh ids remain for the requested page, it skips expensive graph expansion and ranking. The cursor ensures stable pagination across refreshes and hides already served items.
- 3
Candidate generation expands eligible sources
On a cache miss or refresh, the candidate service gathers post candidates from friends, followed pages, groups, recent interactions, friend-of-friend activity, and recommendation sources. It reads social graph edges and affinity scores, but it caps each source to keep candidate size bounded.
- 4
Hybrid fanout merges push and pull candidates
For ordinary producers, candidate ids are already pushed into recipient feed caches by fanout workers. For celebrities, high-degree pages, and large groups, the service pulls recent posts at read time. This avoids writing one viral post into millions of caches while preserving freshness.
- 5
Features are hydrated for ranking
The system fetches viewer-author affinity, post age, content quality, media type, recent engagement velocity, comment quality, hides, reports, dwell-time priors, viewer preferences, and seen-state. Feature retrieval is batched and bounded by strict timeouts.
- 6
ML ranking scores candidates
A tiered ranker first applies cheap filters and lightweight models, then uses a heavier model on the top candidates. The output estimates relevance, meaningful interaction probability, freshness value, negative feedback risk, and policy demotion signals.
- 7
Aggregator applies feed rules
The aggregator deduplicates related stories, removes blocked or deleted content, applies seen-state, enforces group and privacy rules, interleaves ads with organic posts, and ensures diversity across authors and content types.
- 8
Response is hydrated and returned
The Feed API performs final post hydration, checks visibility again, attaches media CDN URLs, comment previews, reaction summaries, and viewer state, then returns the page and next cursor. Large media is fetched directly from the CDN by the client.
- 9
Events update the learning loop
Impressions, clicks, dwell time, hides, reactions, comments, and shares are emitted to the event bus. Consumers update action stores, nearline features, counters, notification pipelines, and future fanout or cache refresh decisions.
Core Components
Feed API
Serves feed pages and coordinates hydration and fallback.
The Feed API is stateless. It handles auth context, cursor validation, cache reads, final visibility checks, response shaping, and graceful degradation. It should not scan the social graph or run heavy ML directly; it delegates those tasks to specialized services.
Candidate Generation Service
Builds a bounded candidate set from many feed sources.
Candidate generation combines pushed cache entries, recent posts from friends, followed pages, groups, friend-of-friend activity, recommendations, and pull-based high-degree sources. It must cap per-source output, deduplicate early, and prioritize candidates likely to survive ranking.
Ranking Service
Scores candidates using ML models and feature stores.
The ranker predicts relevance and negative-feedback risk from graph affinity, content features, engagement velocity, freshness, viewer history, and policy signals. Production systems commonly use a cascade: cheap filters, lightweight ranker, heavier ranker, then business-rule reordering.
Fanout Workers
Push post ids into recipient feed caches for bounded producers.
Workers consume post-created events, look up eligible recipients, and insert post ids into feed caches for normal users and smaller pages or groups. They batch writes, skip inactive recipients when cost is too high, and avoid pushing high-degree producers.
Ranked Feed Cache
Stores precomputed ranked post-id windows per active user.
The cache stores compact lists of post ids, rank scores, rank version, generation time, and cursor metadata. It absorbs most feed reads and lets the system refresh feeds incrementally instead of regenerating a full ranking on every scroll.
Social Graph Store
Stores friend, follow, group, block, mute, and affinity edges.
The graph store supports adjacency-list reads from viewer to followed entities and reverse reads from producer to followers for fanout. It also stores derived affinity features such as close friends, recent interactions, and muted relationships.
Action Store
Captures engagement, comments, counters, seen-state, and ranking signals.
The action store receives high-volume writes for likes, comments, shares, hides, reports, impressions, and dwell events. It maintains raw logs, aggregates, and nearline features. Ranking should tolerate stale features but must not lose critical moderation or block signals.
Media Store and CDN
Stores uploaded media and serves it outside the feed API.
Original images and videos are written to object storage and processed into multiple renditions. CDN edges serve media to clients. Feed responses include metadata and CDN URLs, keeping blob transfer out of the ranking and feed service path.
Deep Dive
Feed ranking is the central problem
A chronological feed is easy to explain but weak for a large social network. A user may follow hundreds of friends, pages, and groups. Some sources post rarely and are highly important; others post frequently and are low value. The feed must rank for predicted value, not just recency.
A mature ranker uses many signals: relationship affinity, post freshness, content type, media quality, comments from close friends, click and dwell history, hides and reports, author quality, group membership, language, location, device, and explicit preferences. The serving system must hydrate these features quickly and degrade safely if some features are stale.
The strongest interview answer separates candidate generation from ranking. Candidate generation narrows millions of possible posts down to hundreds or thousands. Ranking scores those candidates with a latency budget. Aggregation then enforces dedupe, diversity, seen-state, privacy, ad slots, and policy constraints.
Hybrid fanout: push for most, pull for high-degree sources
Pure pull means every feed read scans recent posts from all friends, pages, and groups. That is too slow for users with large graphs and too expensive for billions of reads. Pure push means every post is inserted into every follower cache. That explodes for celebrities, major pages, and large groups.
Hybrid fanout is the usual answer. Push ordinary posts to follower feed caches because the recipient set is bounded and reads become cheap. Pull high-degree sources at read time because their fanout would be massive. The producer can be classified dynamically using follower count, posting rate, engagement velocity, recipient activity, and queue pressure.
Hybrid fanout also improves freshness. A close friend's post can appear quickly through push, while a viral public page can be pulled and ranked when the user opens the app. The candidate service merges both sets and removes duplicates before scoring.
Candidate generation from graph, groups, pages, and friend-of-friend
Candidate generation must be bounded. The system reads the viewer's active friends, close friends, pages, groups, recently interacted authors, and friend-of-friend or recommendation edges. For each source, it takes a small number of recent or high-quality posts and applies early filters for privacy, blocks, mutes, language, and policy.
Friend-of-friend is powerful but dangerous if unconstrained. It can discover socially relevant content, but it expands the graph rapidly and can leak private context. Use explicit public interactions, privacy-safe recommendations, and caps per reason. Keep explainable candidate reasons such as close friend commented or popular in group.
For groups, membership and moderation state are essential. A public group may allow broad discovery, while a private group requires strict membership checks during candidate generation and final hydration.
Feed cache, freshness, pagination, and seen-state
The feed cache should store ranked post ids, not full post bodies. Full bodies change due to edits, deletes, privacy changes, comment counts, and media processing. Storing ids lets the serving path re-check visibility and hydrate current metadata.
Freshness is handled with short TTLs, cache refresh watermarks, and incremental insertion. New close-friend posts can be inserted near the top. Older cached items can remain for pagination as long as the cursor identifies the rank version. If the user pulls to refresh, the system can generate a new head while preserving scroll stability for older pages.
Seen-state prevents repetition. The client reports impressions and visible items, and the server records a dedupe window. The aggregator filters recently seen posts, but can still resurface important updates if comments or shares make them newly relevant.
Ads and organic interleaving
Ads are not simply appended after organic ranking. The feed must reserve eligible slots, request ad candidates, score them for relevance and business constraints, then interleave them without damaging user experience. Frequency caps, advertiser budgets, user preferences, sensitive categories, and policy checks apply.
The organic ranker and ads ranker can be separate, but the final aggregator must compare them through a common utility function or slot policy. It should log why an ad was shown, how it competed with organic content, and whether the user engaged or hid it.
If ads infrastructure fails, organic feed should continue. If organic ranking fails, do not fill the entire feed with ads. Monetization must degrade behind core user experience.
Engagement action store and feature freshness
Likes, comments, shares, hides, reports, impressions, clicks, and dwell time form the feedback loop for ranking. The write path is enormous, so the system records append-only events, computes aggregates asynchronously, and feeds nearline features back to ranking.
Some signals must be fresh. A report or hide should affect future ranking quickly. A viral comment burst may make a post more relevant. Use separate priority lanes: critical safety and negative feedback gets low-latency processing, while bulk counters and offline model training can lag.
Counters should be approximate when needed. Exact global like counts are less important than robust ranking features and low write latency. Use sharded counters, time-windowed aggregates, sketches, and batch compaction to avoid hot rows on viral posts.
Scaling
Prototype: thousands of users
Start with a post store, simple friendship table, chronological query by followed author ids, and a basic ranking formula using recency and affinity. Store media in object storage and serve via CDN from day one. This proves product behavior but will not handle large graphs or high read volume.
Growth: millions of users
Add asynchronous fanout workers, per-user feed caches, Redis or a key-value cache for ranked ids, action logging, and simple ML features. Split post creation from feed reads, and move comment and engagement writes to an event pipeline.
Large scale: hundreds of millions of users
Introduce hybrid fanout, distributed graph storage, sharded action stores, nearline feature stores, ranking model cascades, online experiments, and regional feed caches. High-degree pages and large groups become pull-based sources with bounded candidate budgets.
Planet scale: billions of users
Run multi-region active-active feed serving with local caches, replicated graph and post metadata, global media CDN, per-region ranking fleets, real-time feature pipelines, safety systems, and automated fallback tiers. Keep ranking quality, freshness, and policy enforcement observable per region and cohort.
Bottlenecks & Optimizations
Ranking latency from feature hydration
Batch feature reads, keep online feature stores close to rankers, cache stable features such as affinity, use model cascades, and set strict deadlines. If slow features miss the deadline, rank with defaults rather than delaying the whole feed.
Celebrity and large-page fanout storms
Classify high-degree producers as pull-based, cap fanout recipients, batch writes, prioritize active users, and update cached feed heads opportunistically. Pull recent posts from high-degree sources during candidate generation instead of writing them into every follower cache.
Viral post hot spots in action counters
Use append-only event logs, sharded counters, time-windowed aggregates, and eventual compaction. Avoid a single row for like_count or comment_count. Cache popular post summaries and update them asynchronously.
Feed cache memory and hot shards
Store compact post-id arrays, use TTLs, cache only active users deeply, shard by user id with virtual nodes, compress ids where possible, and regenerate inactive users on demand. Replicate hot shards and rebalance before regional events.
Duplicate or stale feed items
Track seen-state, rank version, source reason, and post canonical id. Deduplicate during candidate merge and final aggregation. Re-check deletion, block, audience, and moderation state during hydration before returning the item.
Media bandwidth and origin pressure
Serve media through CDN, pre-generate common renditions, use adaptive image and video formats, sign URLs when needed, and keep feed API responses to metadata only. Protect object storage with origin shielding and request coalescing.
Failure Handling
Ranking service degraded or unavailable
Serve cached ranked ids if available. If cache is stale, fall back to a lightweight ranking formula using recency, affinity, and content quality. Mark the response with rank version for monitoring and shed heavy model traffic until the fleet recovers.
Feed cache outage
Bypass the cache for a small percentage of users and rebuild from candidate generation with strict quotas. Use circuit breakers to protect graph, post, and action stores. Prefer returning a smaller but valid feed over stampeding all users into full regeneration.
Fanout queue backlog
Feeds remain available through pull-based candidate generation and older cached ids. Workers prioritize close-friend and active-recipient fanout, skip inactive users temporarily, and catch up with batch compaction. Expose freshness lag to ranking and product metrics.
Social graph store partition or replication lag
Use last-known graph snapshots for ranking while enforcing critical block and privacy edges from a strongly replicated safety path. If graph freshness is uncertain, bias toward not showing borderline private content.
Action store or feature pipeline lag
Rank with stale or default engagement features, but process hides, reports, blocks, and deletes through a higher-priority safety lane. Alert on feature freshness because ranking quality can degrade silently.
Media CDN or object-store failure
Return text and metadata with degraded media placeholders, route to alternate CDN origins, and avoid blocking feed ranking on media availability. Uploads can be retried or marked processing while feed reads continue.
Security
Privacy and visibility enforcement
Every returned item must pass final authorization: audience, friendship, group membership, blocks, mutes, deletions, geographic restrictions, age gates, and moderation state. Cached feed ids are only hints, never proof of authorization.
Abuse, spam, and coordinated manipulation
Detect spammy posting, fake engagement, bot actions, coordinated sharing, and malicious links. Downrank or remove abusive content, quarantine suspicious actions, and keep safety features fresher than ordinary engagement counters.
Data minimization and retention
Feed ranking uses sensitive behavioral data. Limit raw event retention, separate personally identifiable data from aggregate features, honor deletion requests, and restrict access to action logs and experiment data.
Scraping and enumeration resistance
Feed APIs expose valuable social content. Enforce authentication, per-user and per-device rate limits, bot detection, cursor integrity, response watermarking, and anomaly detection for large-scale scraping behavior.
Ad and content integrity
Ads and organic content must pass policy checks before serving. Maintain audit logs for ad selection, targeting eligibility, frequency caps, and sensitive-category exclusions. Do not let ads bypass feed visibility or safety checks.
Media safety
Scan uploaded media for malware, known-bad hashes, copyright policy signals, nudity, violence, and other sensitive categories. CDN URLs should respect takedowns quickly through invalidation or deny-list checks.
Tradeoffs
Pros
- +Hybrid fanout keeps ordinary feed reads fast while avoiding massive celebrity fanout writes.
- +Ranked post-id caches reduce online graph expansion and ML scoring cost for the common path.
- +Separating posts, graph, actions, media, and features lets each store scale for its access pattern.
- +A ranking cascade balances model quality with strict p99 latency goals.
- +Asynchronous action processing supports enormous engagement volume without blocking feed reads.
Cons
- −Feed caches can become stale and require final visibility checks on every response.
- −Ranking quality depends on complex feature freshness, model monitoring, and experimentation systems.
- −Hybrid fanout introduces operational complexity and source-specific behavior.
- −Pulling high-degree sources can increase read latency during cache misses or traffic spikes.
- −Ads and policy interleaving make the final aggregation step harder to reason about than simple ranking.
Alternatives
Alternative one is a pure chronological pull feed. It is simple and fresh for small products, but it degrades with large graphs, misses relevance, and makes every feed read expensive.
Alternative two is pure push fanout. It gives very fast reads for bounded graphs, but celebrity pages, large groups, and viral producers create enormous write amplification and hot shards.
Alternative three is fully on-demand ML ranking without per-user feed caches. It can be freshest and most personalized, but scoring hundreds of candidates for billions of read requests is usually too expensive and risky for tail latency.
When not to use this design
Do not build this full architecture for a small community app, an internal activity stream, or a product where chronological order is the core requirement. Start with a simpler pull model and add caching, fanout, and ranking only when graph size, read traffic, and relevance needs justify the complexity.
Follow-up Questions
Why is ranking harder than storing posts chronologically?
A user may have thousands of eligible posts from friends, pages, groups, recommendations, and ads. The system must select what is most valuable now, not simply the newest item. It needs candidate generation, feature hydration, ML scoring, dedupe, privacy checks, seen-state, and business rules within a small latency budget.
When do you push fanout versus pull at read time?
Push when the producer has a bounded follower set, recipient activity is high enough to justify cache writes, and freshness matters. Pull when the producer has millions of followers, posts very frequently, or belongs to a large group or public page where fanout cost would overwhelm write capacity.
What exactly is stored in the feed cache?
Store ranked post ids, scores, rank version, source reason, generation time, cursor metadata, and expiration. Do not store full post bodies as the source of truth. Hydrate posts on read and re-check visibility, deletion, moderation, and viewer state.
How do you keep the feed fresh without reranking everything?
Use incremental cache updates for close-friend and high-value posts, short TTLs for cache heads, pull high-degree sources at request time, and refresh only the top window when the user opens or pulls to refresh. Preserve older rank versions for stable scrolling.
How should seen-state affect ranking?
Seen-state should filter or demote recently exposed posts to reduce repetition, but the system can resurface important posts if new comments, shares, or close-friend activity make them newly relevant. Seen-state must be stored asynchronously but applied before final aggregation.
How do ads fit into the feed design?
Ads are generated and scored separately, then interleaved by the final aggregator using slot rules, frequency caps, relevance thresholds, policy checks, and budget constraints. Organic feed should continue if ads fail, and ads should never bypass privacy or safety constraints.
How do you handle privacy changes after a post is cached?
Treat cached post ids as candidates only. During hydration, check current audience, block, group membership, deletion, and moderation state. Also send invalidation events to feed caches for deletes, blocks, group removals, and policy takedowns, but correctness should not rely only on invalidation.
Company Variations
Meta
Meta interviewers are likely to focus on News Feed ranking, graph scale, hybrid fanout, feature freshness, integrity systems, privacy checks, and ads interleaving. Be prepared to explain why the core is ML ranking plus aggregation, not a chronological timeline.
LinkedIn may frame this around professional network feeds, creator posts, company pages, job-related content, notification-driven engagement, and relevance versus recency. Discuss graph affinity, follow edges, feed explanations, and quality controls for low-frequency but high-value updates.
Google tends to probe ML serving, feature stores, global tail latency, experimentation, and large-scale data pipelines. Expect follow-ups on ranking cascades, candidate pruning, freshness metrics, and how to evaluate quality beyond infrastructure uptime.
Amazon
Amazon may emphasize operational ownership, multi-region reliability, cost, event-driven fanout, and clear degradation plans. Tie each service to alarms, SLOs, backpressure, and the customer impact of stale or unavailable feeds.
Netflix
Netflix can steer the discussion toward personalization quality, ranking experimentation, recommendation pipelines, and UI rows. Compare social feed ranking with recommendation ranking and explain how feedback loops and freshness differ.
Interview Tips
Lead by saying the feed is a ranking system at massive read scale. Draw the read path first: client to Feed API, ranked feed cache, candidate generation, feature hydration, ranker, aggregator, and hydration. Then add the write path: post creation to event bus, fanout workers, post store, action store, and media pipeline. Keep returning to the central tradeoff: freshness versus relevance under a strict ranking latency budget.
What interviewers expect
- ✓State assumptions for DAU, feed reads, posts, actions, fanout, cache size, and media storage.
- ✓Describe candidate generation from friends, pages, groups, graph edges, recommendations, and high-degree pull sources.
- ✓Explain ranking features, ML serving latency, model cascades, and final aggregation rules.
- ✓Use hybrid fanout and feed caches of ranked post ids for scale.
- ✓Cover seen-state, dedupe, privacy, ads, action-store updates, and media CDN.
- ✓Discuss degradation and observability for ranking quality, not just service uptime.
Common mistakes
- !Designing only a chronological query over posts and missing ranking as the core problem.
- !Using pure push fanout for celebrities and large pages without addressing write amplification.
- !Storing full post bodies in feed cache and trusting cached ids without final privacy checks.
- !Ignoring seen-state, deduplication, ads interleaving, and stale cache behavior.
- !Making likes and comments synchronous dependencies of the feed read path.
- !Forgetting media object storage and CDN, then sending blobs through the feed API.
Red flags
- ×No concrete capacity math for billions of users and feed reads.
- ×No separation between candidate generation, ranking, and aggregation.
- ×No fallback when ranking, cache, graph, or action stores degrade.
- ×No privacy enforcement after feed-cache reads.
- ×No explanation of high-degree producers or hybrid fanout.
Revision Notes
- The core of Facebook Feed is ranking, not chronological storage.
- Use candidate generation to narrow sources from friends, pages, groups, friend-of-friend, recommendations, and high-degree producers.
- Use hybrid fanout: push ordinary producers to feed caches, pull celebrities, large pages, and large groups at read time.
- Store ranked post ids in the feed cache, not full post bodies. Hydrate posts and re-check privacy on every response.
- For 2B DAU and 20 feed page requests per day, expect 40B feed reads per day, about 463K average QPS, and multi-million QPS peaks.
- For 300M posts per day and 95 percent push fanout to 300 recipients, expect about 85B feed-cache inserts per day.
- Likes, comments, shares, hides, reports, impressions, clicks, and dwell events belong in an action store and event pipeline.
- Ranking features must be fresh enough for quality, but feed reads should tolerate stale non-critical features.
- Final aggregation handles dedupe, seen-state, diversity, privacy, policy, freshness, and ads or organic interleaving.
- Media belongs in object storage and CDN. Feed APIs return metadata and URLs.
Flashcards
Quiz
0/7 answered
1.What is the most important design focus for Facebook Feed at scale?
2.Why use hybrid fanout?
3.What should be stored in a ranked feed cache?
4.Given 2B DAU and 20 feed page requests per user per day, what is the average feed read QPS?
5.Why must the serving path re-check visibility after reading cached post ids?
6.Which engagement signals should feed into ranking and action stores?
7.What is the best degradation if the heavy ranking model is unavailable?
Cheat Sheet
Goal: return a personalized, ranked, privacy-correct feed page for billions of users with about 200ms p99 regional latency.
Core crux: not chronological storage. The core is candidate generation, feature hydration, ML ranking, and aggregation under strict latency and cost limits.
Workload: 2B DAU, 20 feed pages per user per day, 40B feed reads per day, about 463K average QPS, and about 4.6M peak QPS.
Writes: 300M posts per day, 20B actions per day. Ordinary posts are pushed to feed caches; high-degree pages, celebrities, and large groups are pulled at read time.
Feed cache: per-user ranked post-id windows with rank version, cursor, score, timestamp, and TTL. Store ids only; hydrate and authorize posts on every read.
Candidate generation: merge friends, pages, groups, friend-of-friend, recommendations, pushed cache entries, and pull-based high-degree sources. Bound candidates per source.
Ranking: use affinity, freshness, engagement velocity, content quality, viewer history, negative feedback, policy, and seen-state. Use cascaded models and feature deadlines.
Aggregation: dedupe, filter seen or hidden posts, enforce privacy, diversify authors and content types, interleave ads, and attach media CDN URLs.
Storage: graph store for edges, post store for metadata, feed cache for ranked ids, action store and event log for engagement, object store plus CDN for media.
Failure plan: cached feed first, then lightweight ranker, then chronological or affinity fallback. Never bypass privacy or safety checks.
References
- PaperTAO: Facebook's Distributed Data Store for the Social Graph — Nathan Bronson et al.
- PaperScaling Memcache at Facebook — Rajesh Nishtala et al.
- PaperDeep Learning Recommendation Model for Personalization and Recommendation Systems — Maxim Naumov et al.
- PaperThe Tail at Scale — Jeffrey Dean and Luiz Andre Barroso
- BookDesigning Data-Intensive Applications — Martin Kleppmann