Back to System Design
System Design
hard
mid

How would you design a news feed for a product like Facebook?

Infinite-scroll feed with cursor pagination; virtualized list for large scrolls; per-post components with mixed media; optimistic likes/comments; ranking served by backend; client caches via React Query keyed on cursor; image/video lazy-load; offline / poor-network resilience; accessibility for the post structure and live updates.

5 min read·~30 min to think through

A news feed at scale is the canonical frontend system-design question. The architecture is infinite scroll over server-ranked, cursor-paginated posts, with optimistic interactions and aggressive media optimization.

1. Pagination — cursor, not offset

Offset pagination breaks when items are inserted at the top of a feed (you'd see duplicates / skips). Cursor pagination (server returns an opaque cursor with each page) is correct:

ts
GET /feed?cursor=eyJ...
→ { items: [...], nextCursor: "eyJ..." }

2. Infinite scroll — IntersectionObserver

Sentinel at the bottom of the rendered list:

jsx
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
  queryKey: ["feed"],
  queryFn: ({ pageParam }) => fetchFeed(pageParam),
  getNextPageParam: (last) => last.nextCursor,
});

const ref = useRef();
useEffect(() => {
  const obs = new IntersectionObserver((entries) => {
    if (entries[0].isIntersecting && hasNextPage) fetchNextPage();
  });
  if (ref.current) obs.observe(ref.current);
  return () => obs.disconnect();
}, [hasNextPage]);

3. Virtualization

Without virtualization, 10k rendered posts kill memory and scroll perf. react-virtual / react-window for fixed-ish heights; for variable heights, measure and cache.

4. Post component

ts
<Post>
<Header (avatar, name, time, menu) />
<Body (text, embeds) />
<Media (image/video/link preview) />
<Actions (like, comment, share) />
<Comments (preview, expandable) />

Memoize so liking one post doesn't re-render the feed.

5. Interactions — optimistic

Like, react, comment — all optimistic with rollback on failure. Idempotency keys for retry safety.

6. Media

  • Lazy load below the fold (IntersectionObserver or loading="lazy").
  • Responsive images with srcset; modern formats (WebP/AVIF).
  • Video — autoplay only when in view, muted, controls on tap.
  • Aspect-ratio reserved to prevent CLS.

7. Ranking

Backend concern (engagement model, recency, social graph). Frontend's job is to render the order it receives and not re-sort.

8. Caching

  • React Query keyed on cursor — back-navigation restores the scroll position with a warm cache.
  • Persist the first page to localStorage for an instant offline-y open.
  • Invalidate selectively on post-create.

9. Real-time updates

  • New posts above — a "Show N new posts" pill (don't auto-shift the scroll).
  • New comments/likes — push via WebSocket or poll counts periodically.

10. Performance & resilience

  • Code-split heavy components (video player, reactions picker).
  • Skeleton placeholders matching post layout.
  • Retry with backoff on transient errors.
  • Service worker for offline shell + cached feed.

11. Accessibility

  • Each post is an <article> with an accessible name.
  • Image alt text; video captions.
  • Keyboard: J/K to next/prev post (FB does this), focus management on expanding comments.
  • Live region for "new post" announcements (polite).

Interview framing

"Feed scrolls infinitely with cursor pagination — offset breaks as new posts arrive at the top. IntersectionObserver triggers fetchNextPage; React Query keyed on cursor caches pages so back-nav restores state. Virtualize the list once it's long. Each post is a memoized component; likes and comments are optimistic with idempotency keys. Media is the heaviest cost: lazy-load, responsive srcset, modern formats, reserved aspect-ratio. New top-of-feed posts surface as a 'Show N new' pill rather than auto-shifting. Ranking is the server's problem; the client renders the order received."

Follow-up questions

  • Why cursor pagination instead of offset?
  • How do you handle new posts arriving while the user is scrolled?
  • Virtualization with variable-height posts — how?
  • How would you make the feed resilient to network failure?

Common mistakes

  • Offset pagination — duplicates/skips as content shifts.
  • Rendering everything; no virtualization.
  • Auto-jumping the scroll on new posts.
  • Not memoizing posts — like one, re-render thousand.
  • No aspect-ratio on media — CLS.

Performance considerations

  • Virtualize + memoize posts. Lazy-load + decode-async images. Code-split heavy interactions. Throttle scroll handlers via rAF or IntersectionObserver (not scroll-event polling).

Edge cases

  • Very tall posts (long text, multiple images).
  • Network drops mid-scroll.
  • Switching feed (Home → Profile) — separate cache keys.
  • Rapid scroll past unloaded items.

Real-world examples

  • Facebook News Feed, Twitter/X timeline, Instagram feed, Reddit.

Senior engineer discussion

Seniors separate concerns cleanly: server ranks and paginates with cursors; client renders, caches, and handles optimistic interactions. They virtualize, memoize, and treat media optimization as the dominant performance lever — not micro-CSS tweaks.

Related questions