How does the For You feed actually get built?
In stages, by a pipeline called the Home Mixer. First, sources gather candidate posts — Thunder pulls in-network posts from accounts you follow, Phoenix retrieves out-of-network posts you don't. Then hydrators enrich each candidate with features (engagement counts, video duration, whether the author blocks you). Filters drop the ineligible. Scorers rank what survives — the weighted scorer, the out-of-network handicap, author diversity. Selectors pick the final set, ads get blended into safe gaps, and the result is serialized into your timeline. Every post you see ran this gauntlet.
The feed isn't ranked in one step — it's assembled by a pipeline, and the released code lets us name every stage. The orchestration lives in the Home Mixer's For You server, which runs a candidate pipeline and serializes the result into your timeline:
36let result = self.pipeline.execute(query).await; 37 38Ok(ForYouFeedOutput { 39 items: result.selected_candidates, 40})
The For You feed is assembled by a Home Mixer candidate pipeline: the server calls pipeline.execute(query) and serializes the selected_candidates into the timeline. The pipeline composes sources, hydrators, filters, scorers, and selectors.
The five stages
The pipeline is a fixed sequence of component types, each with one job:
| stage | what it does |
|---|---|
| Sources | Gather candidates. Thunder for in-network (your follows), Phoenix for out-of-network, Who-To-Follow for account suggestions. |
| Hydrators | Attach features to each candidate — engagement counts, video duration, whether the author blocks you, language. |
| Filters | Remove the ineligible — already-seen posts, muted keywords, duplicates, age, your own posts. |
| Scorers | Rank what's left — the 19-signal weighted scorer, the out-of-network multiplier, author-diversity decay. |
| Selectors | Pick the final ordered set; ads are blended into safe gaps before serving. |
Sources: two retrieval paths
Your feed is built from two fundamentally different candidate streams.
Thunder fetches posts from the accounts you
follow; Phoenix retrieves relevant posts from the wider network. They are separate services with
separate code, and a post's path into your feed depends on which one surfaced it.
Candidates are gathered by multiple sources, including Thunder (in-network posts from accounts the viewer follows) and Phoenix (out-of-network retrieval), plus a Who-To-Follow source for account recommendations.
Filters: the quiet gate
Before anything is scored, filters remove candidates outright. The release includes filters for
previously-seen and previously-served posts, muted keywords, conversation deduplication, age,
your own posts, and more. A post filtered here never reaches scoring — it's not that it ranked
low, it's that it was never eligible.
Before scoring, Home Mixer removes: duplicates, posts that failed metadata hydration, posts older than a threshold, your own posts, repost duplicates, paywalled content you can't access, posts you've already seen or been served, posts containing your muted keywords, and posts from authors you've blocked or muted.
Why the order matters
The sequence is the strategy. Sourcing decides what's even considered. Filtering decides what's eligible. Only then does scoring decide order. This is why "my post scored low" and "my post was filtered out" are different problems with different fixes — and why getting retrieved matters before ranking can help you at all. Each stage has its own page in this pillar.
What the code doesn't say
The exact component ordering and which are active in production. The released pipeline shows
the component types and many concrete implementations, but the precise runtime
configuration — which filters run, in what order, with which parameters — depends on the withheld
params module and deploy-time config. The architecture is code-current; the exact
production assembly is not fully in the open.
The numeric values of the current weights are not included in the open-source release: weighted_scorer.rs references a params module (e.g. p::FAVORITE_WEIGHT, p::REPLY_WEIGHT) whose values are not present anywhere in the published repository.
What to do with this
Think in stages, not in a single score. If your reach is off, ask which stage is the problem: are you not being sourced (a retrieval/relevance issue), being filtered (eligibility — muted terms, dedup, age), or being outscored (the signals on the formula page)? xDoctor's diagnostics map to these stages, which is what makes "why did this post die" answerable instead of mysterious.