Frontend system design: design Video Streaming (Netflix)
HLS/DASH adaptive bitrate streaming via a player (Shaka/Video.js) sourced from a CDN; manifest + segmented chunks; ABR algorithm picks quality based on bandwidth + buffer; preload posters and metadata; SSR/SSG the catalog pages for SEO and fast LCP; per-row carousels; auth-gated playback; accessibility (captions, focus, keyboard).
Netflix-style video streaming is an architecture question with two halves: the catalog/browse UX, and the player/streaming pipeline.
1. Catalog & browse
- SSR/SSG the home/browse pages for SEO and a fast first paint (large hero, lazy-loaded rows).
- Per-row carousels — horizontal scroll with prefetch on hover, virtualized if rows are long.
- Edge caching at the CDN for the catalog API (with personalization handled via a thin per-user merge or client-side reordering).
- Image-heavy — responsive posters with
srcset, blurred placeholders to mask LCP.
2. Player — adaptive bitrate (HLS / DASH)
You do not stream a single MP4. Video is chunked (~2–10s segments) at multiple bitrates, described by a manifest (.m3u8 for HLS, .mpd for DASH).
- The player downloads chunks; the ABR (adaptive bitrate) algorithm picks the next chunk's quality based on measured bandwidth and current buffer level.
- CDN-served chunks for low latency globally.
- DRM (Widevine, FairPlay, PlayReady) for protected content.
In the browser, use Shaka Player or Video.js / hls.js — building this yourself is a years-long project.
<video id="player" controls></video>
<script>
const player = new shaka.Player(document.getElementById("player"));
await player.load("/manifests/title-1234.mpd");
</script>3. Buffering UX
- Show a loading state when the buffer is low.
- Pre-buffer ahead a few segments while playing.
- Pause/resume preserves position; on resume, fetch the next segment.
- "Continue watching" — persist last position per user.
4. Preloading & prefetching
- Hover on a title card → fetch the title's metadata + start the preview clip.
- Posters lazy-loaded below the fold.
- Next-episode prefetch in the final seconds.
5. State & data
- Server state via React Query: catalog, rows, search.
- UI state (player open, captions on) local or via player API.
- User state (profile, history) auth-scoped.
6. Personalization
- Rows are personalized server-side; client just renders.
- Watch progress is written back with a debounce (every 30s + on pause/end).
7. Performance
- Code-split the player (heavy) from the catalog shell.
- Defer DRM init until play is pressed.
- LCP is usually the hero — preload its poster.
- Memory: free player resources on unload to avoid leaks.
8. Accessibility
- Captions / subtitles — toggle, language selection.
- Keyboard: Space play/pause, ←/→ seek, F fullscreen, M mute.
- Focus management when entering/exiting fullscreen.
- Audio descriptions for visually impaired users.
9. Resilience
- Network drop → buffer drains → player shows "Connecting..." and retries.
- Quality drops automatically as bandwidth falls (ABR).
- DRM errors surface a clean message, not a stack trace.
Interview framing
"Two halves: catalog and player. Catalog is SSR/SSG for SEO and LCP, horizontal carousels per row, posters lazy-loaded via srcset, edge-cached APIs. The player is HLS or DASH — chunked video at multiple bitrates with a manifest; the player picks quality per chunk based on bandwidth and buffer. We don't build this — Shaka or Video.js. DRM via Widevine/FairPlay/PlayReady. Continue-watching persists last position. Accessibility is a first-class concern: captions, keyboard, focus on fullscreen. Performance: code-split the player, preload the hero poster, lazy everything else."
Follow-up questions
- •What's an adaptive bitrate algorithm doing?
- •Why HLS/DASH instead of an MP4?
- •How would you implement 'continue watching'?
- •What's the LCP for a Netflix-style page and how do you optimize it?
Common mistakes
- •Streaming a single big MP4 with no adaptation.
- •Loading the heavy player on the catalog page upfront.
- •Not lazy-loading posters.
- •Skipping captions / keyboard.
Performance considerations
- •LCP is the hero poster; ABR handles bandwidth adaptation; code-split the player; preload upcoming segments while playing; free player resources on unload.
Edge cases
- •Bandwidth crashes mid-playback — ABR drops quality.
- •DRM license expiry mid-session.
- •Resume after long pause — re-auth and resync position.
- •Multiple tabs playing the same title.
Real-world examples
- •Netflix, YouTube, Disney+, Hulu — all use HLS/DASH + ABR + CDN.