Design an Instagram-like feed page
Vertical infinite-scroll feed of posts (image/video, caption, likes, comments). Cursor-paginated, virtualized for memory; aggressive image/video lazy-load with placeholders and autoplay-on-visible; optimistic likes/comments; stories carousel above feed; pull-to-refresh; double-tap-to-like; SSR/SSG home for SEO; service worker for offline shell.
An Instagram-style feed is a polished example of patterns from [[frontend-system-design-design-a-news-feed-facebook]] — vertical media-heavy posts with very specific interaction details. The interview wants both the architecture and the Instagram-specific UX choices.
1. Feed mechanics
- Cursor-paginated server feed (offset breaks under inserts).
- IntersectionObserver sentinel near the bottom triggers next-page fetch.
- Virtualization for memory — discard far-off-screen posts.
- Pull-to-refresh to fetch new posts above current top; insert without auto-shifting (show "N new posts" pill if user is scrolled).
2. Post structure
<Post>
├ <Header> avatar, username, ⋯ menu
├ <Media> image / video / carousel
├ <Actions> like, comment, share, save
├ <LikesCount>
├ <Caption> username + truncated text
├ <Comments> top 2 + "View all 142 comments"
└ <Timestamp>Memoize so liking one post doesn't re-render the feed.
3. Media — autoplay on visible
For video posts:
muted,playsinline, autoplay when ≥ 50% in viewport (IntersectionObserver).- Pause when scrolled away.
- Aspect-ratio reserved for both images and videos to prevent CLS.
- HLS / DASH for non-trivial video (see [[frontend-system-design-design-video-streaming-netflix]]).
- Image carousels (multi-image posts) — horizontal scroll-snap, pagination dots, lazy-load slides.
4. Likes — double-tap + optimistic
- Double-tap on media → like (with the iconic heart-burst animation).
- Optimistic — bump count, fill heart, send mutation in background, rollback on failure.
- Idempotency key so retries don't double-like.
5. Comments
- Show first 1–2 + "View all" expanding inline or on tap.
- Compose box with submit; optimistic insertion at top.
- Replies threaded (collapse/expand).
6. Stories carousel
A horizontal strip at the top — separate component, separate data source. Tap into a story → modal/route with stories viewer (tap-and-hold to pause, swipe between users, auto-advance).
7. State & data
- React Query keyed on
(feed, cursor)so back-nav restores scroll + data. - UI state (story modal open, comments expanded) local.
- Caches invalidated on new-post creation.
8. Rendering strategy
- SSR/SSG home for SEO and fast first paint (LCP = first post's image).
- Hydrate for interaction.
- Subsequent navigation is client-side.
9. Performance
- LCP = first visible image — preload it (Next
<Image priority>). - Image optimization — responsive
srcset, AVIF/WebP, blurhash placeholders. - Code-split heavy paths (stories viewer, DMs).
- Memoize posts; transform-only for any tap animations.
10. Real-time
- WebSocket for new likes/comments on visible posts (count updates).
- Optimistic-vs-broadcast reconciliation — don't bump a count twice if your own action echoed back.
11. Resilience
- Network drop → retry transparently; queue mutations (likes, comments).
- Service worker for offline shell (cached feed page renders even offline; new posts gated on network).
12. Accessibility
- Post as
<article>with descriptive name. - Image
alttext (server-supplied; allow user-supplied for posts they upload). - Video captions / subtitles where available.
- All interactive icons have labels ("Like this post by @anya").
- Live region announces new likes/comments while scrolled.
Interview framing
"Vertical infinite-scroll feed, cursor-paginated, virtualized once long. Each post is a memoized component; videos autoplay muted on ≥50% visibility via IntersectionObserver and pause when out. Double-tap-to-like is optimistic with idempotency; likes/comments update locally first, sync to server, rollback on failure. Stories are a horizontal strip with their own viewer. Pull-to-refresh fetches new posts but doesn't auto-shift — surfaces a 'N new posts' pill instead. SSR/SSG the home page for LCP and SEO. The dominant perf cost is media — modern formats, responsive sizes, blurhash placeholders, preload the LCP image."
Follow-up questions
- •Why cursor pagination instead of offset?
- •How do you autoplay only the visible video?
- •Why surface a 'New posts' pill rather than auto-inserting?
- •How does optimistic like work end-to-end?
Common mistakes
- •Offset pagination — duplicates as new posts arrive.
- •Auto-shifting the scroll when new posts arrive.
- •All videos playing at once.
- •No memo on posts → like → re-render the world.
- •No CLS reservation on media.
Performance considerations
- •Media dominates. Autoplay only the visible video. Memoize posts. Virtualize once feed is long. Preload LCP image. Service worker shell for repeat loads.
Edge cases
- •Network drop mid-scroll.
- •Carousel post with 10 images.
- •User scrolls fast past unloaded video.
- •Two devices, same user, both liking.
Real-world examples
- •Instagram, TikTok, Twitter/X.