Knowledge Guide
HomeHands-On BuildsSD Design Labs

Design YouTube / Netflix

Design YouTube / Netflix (upload, transcode, store, stream at scale)

The naive pitch sounds reasonable for about ten seconds: "the user uploads a video file, we save it to disk, and when someone hits play we stream that file back." Then reality arrives. The uploaded file is one encoding at one bitrate — but a viewer on a 4K TV wired to fibre and a viewer on a phone crawling along on 3G cannot both be served the same bytes: give the phone the 4K file and it buffers forever; give the TV a 480p file and it looks like mud on a 65-inch screen. And even if you solved the quality problem, serving every playback read straight from your origin storage means pushing the entire global viewing bandwidth — which we'll compute at ~125 Tbps average — out of your own data centre, from the same handful of servers that hold the hot files. Video is the canonical "the write is easy, the read will bankrupt you" system: one system to ingest and transcode, a completely different system to deliver. This lab derives both from first principles, with every number traced so you can defend it under drilling.

Movement 1 — The Trap: "store the file, stream it back"

Picture the simplest thing that could possibly work. A creator uploads a 2-hour 4K movie. You store that single file in object storage. When anyone presses play, your web server opens the file and streams the raw bytes to their player. Ship it. Here is exactly where it detonates, quantified:

The trap is treating video as a storage problem. It's a bandwidth problem wearing a storage costume, and the fix is two ideas the naive design lacks entirely: (1) transcode the one upload into a ladder of bitrates cut into small segments so the client can adapt, and (2) push those segments to edge caches so ~99% of bytes never touch your origin.

Movement 2 — Scope it like a senior (ask before you draw)

Do not touch the whiteboard yet. Each of these answers changes the design materially:

Assume for this lab: 500 hours of video uploaded per minute; ~1 billion hours watched/day; VOD (not live); a rendition ladder of 240p / 360p / 480p / 720p / 1080p (4K for a subset); playback must start in <1 s; content kept indefinitely but cold content tiered to cheaper storage; global audience across mobile / web / TV.

Movement 3 — Reason to the design (derive it, don't recite it)

Step 1 — kill the "one file for everyone" problem: transcode into a bitrate ladder. The upload arrives in one format; we re-encode it into several renditions (240p…4K), each a different resolution/bitrate. Now a phone can request 360p and a TV can request 1080p — same video, different bytes. But a whole-file-per-rendition still can't adapt mid-stream: if the phone's bandwidth drops halfway through, it's stuck on whatever rendition it started.

Step 2 — cut every rendition into short segments so the client can switch on the fly. Chop each rendition into 2–10 second segments (HLS or MPEG-DASH). The client fetches a manifest (the list of renditions and their segment URLs), then pulls segments one at a time. Because each segment is an independent little file, the player can fetch segment 5 in 720p, notice bandwidth dropped, and fetch segment 6 in 480p — adaptive bitrate streaming (ABR). Blurry beats buffering: the client always picks the highest rung it can sustain without stalling. Crucially, transcoding is now embarrassingly parallel — different segments and different renditions are independent jobs, so a worker fleet chews through one upload in parallel (the data-parallel/map pattern).

Step 3 — decouple ingest from viewing with a queue + blob store. The upload service shouldn't block while a video transcodes (that can take minutes). It stores the raw master in a blob/object store, drops a job on a message queue (see Introduction to Kafka), and returns. A worker fleet consumes jobs, transcodes, and writes the rendition×segment files back to the blob store. The queue is what lets ingest survive a spike (a celebrity dump of 10,000 uploads) — work backs up in the queue instead of knocking the system over.

Step 4 — the crux for read scale: CDN edge caching. The segment blob store is the origin. If every play read from origin we're back in the 125 Tbps trap. Instead we push/pull popular segments to CDN edge servers in every region. A viewer's player fetches segments from the nearest edge; ~99% of bytes are served from the edge, so origin egress collapses from ~125 Tbps to ~1.25 Tbps. This single decision is what makes global video financially possible — it's not an optimization, it's the architecture of the read path.

Putting it together: upload → (chunked/resumable) upload service → raw blob store → transcode queue → worker fleet fans out the ladder & segments → segment blob store (origin) → CDN edges → client ABR player picks the rung. Two independent systems: a write-once ingest pipeline and a massively-cached read path. Now we size it.

Movement 4 — Build it: the design worksheet

This is the artifact you'd produce in a 45-minute round. Work it in order; every number below is traced, not asserted — recompute it yourself before an interview.

Functional requirements

Non-functional requirements

1. Back-of-envelope estimation (BOTE) — arithmetic visible

2. API sketch

// --- Upload (resumable / chunked) ---
POST /videos                      -> 201 { video_id, upload_url }   // create, get an upload session
PUT  /upload/{video_id}?chunk=k   -> 204                            // idempotent chunk PUT (retry-safe)
POST /upload/{video_id}/complete  -> 202 { status: "transcoding" }  // assemble + enqueue transcode

// --- Playback ---
GET  /videos/{video_id}/manifest.m3u8   -> 200 (HLS/DASH manifest: renditions + segment URLs)
GET  /segments/{video_id}/{rendition}/{seg}.ts  -> 200 (served from CDN edge, ~99% of the time)

// --- Metadata / social (separate read-heavy services) ---
GET  /videos/{video_id}           -> { title, owner, thumbnails, duration, view_count }
POST /videos/{video_id}/view      -> 204   // async counter increment (its own classic problem)

3. Data model & partitioning

4. High-level diagram — ingest pipeline (top) vs cached delivery (bottom)

The ingest path (blue) is write-once: chunked upload → raw master → queue → worker fleet fans out the ladder and segments → segment blob store. The delivery path (green) reads almost entirely from CDN edges; only an edge miss pulls from the origin blob store. The queue (amber) is the shock absorber that keeps an upload spike from taking down transcode.

YouTube/Netflix architecture. Top row (ingest, blue): Uploader sends chunked/resumable uploads to the Upload Service, which stores the raw master in the Raw Blob Store and enqueues a job on the Transcode Queue (Kafka). The Transcode Worker Fleet fans out the rendition ladder 240p to 4K, cuts each into 2-10s segments, and writes them to the Segment Blob Store, which is the origin for delivery; a Metadata and Manifest DB holds the HLS/DASH m3u8. Bottom row (delivery, green): the Client ABR Player fetches the manifest, then pulls segments from the nearest CDN Edge PoP, which serves about 99% of bytes and only pulls from origin on an edge miss. Egress about 125 Tbps average is the dominant cost; 99% CDN offload drops origin egress to about 1.25 Tbps.
YouTube/Netflix architecture. Top row (ingest, blue): Uploader sends chunked/resumable uploads to the Upload Service, which stores the raw master in the Raw Blob Store and enqueues a job on the Transcode Queue (Kafka). The Transcode Worker Fleet fans out the rendition ladder 240p to 4K, cuts each into 2-10s segments, and writes them to the Segment Blob Store, which is the origin for delivery; a Metadata and Manifest DB holds the HLS/DASH m3u8. Bottom row (delivery, green): the Client ABR Player fetches the manifest, then pulls segments from the nearest CDN Edge PoP, which serves about 99% of bytes and only pulls from origin on an edge miss. Egress about 125 Tbps average is the dominant cost; 99% CDN offload drops origin egress to about 1.25 Tbps.

5. Rubric — what a strong answer hits

Movement 5 — Break it: three traced failures

1. Transcode-queue backlog on a viral upload spike. Steady state, ingest is ~720,000 hours/day = ~500 hours/min of work, and the worker fleet is sized for that plus headroom. Now a coordinated event (a game launch, thousands of creators uploading a reaction within the hour) triples upload rate for 30 minutes. If the upload service transcoded synchronously, every uploader would time out and the API would fall over. Because ingest drops jobs on a queue, the spike simply grows the queue depth: work that would have finished in 2 minutes now finishes in, say, 20 — new videos are watchable later, but nothing crashes, and no upload is lost. The lesson: the queue converts an availability failure (synchronous overload) into a latency degradation (delayed transcode), which is exactly the trade you want for a background job. Scale the fleet on queue depth (autoscaling), and prioritize the queue (a monetized/live upload jumps ahead of a hobbyist's).

2. Origin bandwidth blowup on a cache-miss storm. A video goes viral in a region where it isn't yet cached at the edge. Every one of the first wave of players misses the edge and the edge pulls the same segments from origin — a thundering herd on the origin blob store. Trace the sensitivity from the BOTE: origin egress scales with (1 − hit_ratio), so if a hot event drags the effective hit ratio from 99% to 95%, origin egress jumps from ~1.25 Tbps to ~6.25 Tbps (5×) — potentially past what the origin tier is provisioned for, which then fails more requests, which pushes more load to origin: a feedback spiral. Fixes: request coalescing at the edge (many identical misses collapse into one origin fetch, not thousands), a regional mid-tier cache (shield) between edge and origin so a miss hits the shield not the origin, and pre-warming (push a predicted-viral video to edges before the wave). This is why the cache hit ratio is the single number to defend — it's a multiplier on the most expensive resource in the system.

3. A 20 GB upload dies at 90% on a flaky connection. A creator on hotel Wi-Fi uploads an 18 GB 4K master; at 90% the connection drops. With a naive single POST, the whole upload is lost and they start from zero — and they'll rage-quit before it ever succeeds. The fix is chunked, resumable upload: split the file into (say) 5–10 MB chunks, PUT each independently and idempotently (re-PUT a chunk safely on retry), and track which chunks landed. On reconnect the client asks "which chunks do you have?" and resends only the missing ones. The complete call assembles them server-side and enqueues transcode. Lesson: for large files over the public internet, the upload itself is a distributed-systems problem — you design for partial failure and retries, not a happy-path single request.

Movement 6 — Optimise, with trade-offs vs named alternatives

DecisionOption AOption BPick when
When to transcodeTranscode-on-upload (precompute the full ladder eagerly)Transcode-on-demand (lazily encode a rendition the first time it's requested)On-upload for the head (popular content must be instantly streamable, and you want the ladder ready before the viral wave). On-demand (or a smaller eager ladder) for the cold tail — with ~180K cores of transcode cost, precomputing 4K for videos nobody watches is pure waste. Real systems do hybrid: eager for the common rungs, lazy for the rare ones.
Delivery formatHLS/DASH adaptive (segmented ladder)Single-bitrate progressive downloadAdaptive almost always at this scale — it's the only thing that serves a 3G phone and a 4K TV from one video and adapts mid-stream (blurry beats buffering). Single-bitrate only for a controlled environment where every client has known, stable bandwidth (an internal kiosk) — it can't handle the open internet's variance.
Getting content to the edgePush-to-CDN (proactively replicate to edges)Pull-through / origin-pull (edge fetches on first miss, then caches)Pull-through as the default — you can't afford to push 1.2 EB/yr of the long tail to every edge; let popularity decide what caches. Push selectively for known hot content (a Netflix original's launch night, a scheduled premiere) to pre-warm edges and dodge the cache-miss storm (Break It #2). Most real CDNs combine both.
Rendition storage for the tailStore all renditions for every video forever, all on hot storageTranscode-popular-only + tier cold masters/renditions to archive storageTier + selective for the tail — at ~1.2 EB/yr, keeping every 4K rendition of every unwatched video on hot storage is unaffordable. Keep the master durable, keep popular renditions hot near the CDN, and push cold content to cheap archive; re-transcode-on-demand if a dormant video suddenly gets views. Store-all-hot only makes sense for a small catalog where storage is trivial next to engineering effort.
View-count accuracyExact, synchronous increment on every playAsync / eventually-consistent counter (aggregate off a stream)Async almost always — a synchronous DB write on the hottest read path (every play) would bottleneck the money path for a number nobody needs to be exact in real time. Aggregate view events off a queue/stream; accept a slight lag. Exact-synchronous only where the count is transactional (e.g. paid-per-view billing).

Movement 7 — Defend under drilling

Q1 — "Walk me through exactly what happens when I hit play."
The player first fetches the manifest (.m3u8/DASH MPD) — the list of available renditions and, per rendition, the ordered segment URLs. To hit the <1 s time-to-first-frame target it deliberately starts at a low rung so the first segment downloads fast, then requests segments from the nearest CDN edge. As it downloads, it measures its own throughput and buffer level and, for each next segment, requests the highest bitrate it can sustain without draining the buffer. ~99% of those segment bytes come from the edge; the origin is only touched on an edge miss.

Q2 — "How does adaptive bitrate actually decide which resolution to pick?"
The client (not the server) runs the ABR algorithm. Two signal families: throughput-based (estimate recent download bandwidth from how fast the last few segments arrived, pick the highest rung below that estimate with a safety margin) and buffer-based (if the playback buffer is draining toward empty, step down aggressively even if bandwidth looks fine; if the buffer is comfortably full, step up). Production players (e.g. BOLA-style, or hybrids) blend both. The design invariant is blurry beats buffering — a lower rung that plays smoothly always wins over a higher rung that stalls. This is why we segment: switching rungs is just "request the next 4-second chunk from a different rendition," no re-buffering the whole stream.

Q3 — "A video suddenly goes viral in a region where it's not cached. What happens, and what do you do?"
The first wave misses the edge, so edges pull from origin — a thundering herd (Break It #2). Three defenses, layered: request coalescing at the edge so N identical concurrent misses become 1 origin fetch; a regional shield / mid-tier cache so an edge miss hits the shield, not the origin; and predictive pre-warming — signals like a spiking view rate or a scheduled premiere trigger pushing the segments to edges ahead of the wave. Because segments are immutable, once they're at the edge the video serves from cache indefinitely with zero invalidation risk. The origin only ever sees the thin leading edge of the wave, not its bulk.

Q4 — "Why a queue for transcode? Why not just transcode in the upload request?"
Transcoding a video into the full ladder takes minutes and ~6 core-hours — you can't hold an HTTP request open that long, and doing it inline couples upload availability to transcode capacity, so an upload spike would take down the upload API itself. The queue decouples them: ingest returns immediately after durably storing the master and enqueuing; the worker fleet drains the queue at its own pace and autoscales on queue depth. It also lets us prioritize (monetized/live jumps the line) and retry failed transcodes without the uploader ever knowing. The cost is that a new video is watchable in minutes, not instantly — acceptable for VOD.

Q5 — "How would you handle live streaming instead of VOD?"
Live flips two things. First, you can't precompute — you transcode in near-real-time as the stream arrives, producing segments continuously with a target end-to-end latency of a few seconds (low-latency HLS/DASH shrink segments to sub-second and use chunked transfer). Second, the manifest is a sliding window that keeps appending new segments rather than a fixed list. Everything else survives: still a rendition ladder, still ABR on the client, still CDN edges (with very short cache TTLs on the live segments and manifest). The hard new constraint is the latency budget on the ingest+transcode path, where VOD had all the time in the world.

Q6 — The 100× escalation: "Now it's 100× the traffic — ~12,500 Tbps average egress. What breaks first, and what do you do?"
Storage and transcode scale horizontally almost linearly (more blob capacity, more workers off the same queue) — those aren't the wall. The wall is egress: 12,500 Tbps is beyond any single CDN's capacity and beyond what you'd want any one region's peering to carry. Answers: (1) multi-CDN — spread across several CDN providers with steering by cost/health/geography (also removes the single-CDN SPOF); (2) push harder on hit ratio — every point of hit ratio is a multiplier on origin egress, so at this scale even 99.9% vs 99% is enormous, justifying bigger edges and smarter pre-warming; (3) ISP-embedded caches (Netflix Open Connect / Google's edge nodes physically inside ISP networks) so the hottest content is served from inside the last-mile network and never crosses a peering link at all; (4) tier the cold long tail ruthlessly so hot storage and premium edge capacity are spent only on content that's actually watched. The through-line: at 100×, the problem is entirely "get bytes as close to the eyeball as possible and serve as few as possible from origin."

Movement 8 — You can now defend


Re-authored/Deepened for this guide. Model-answer reading: Designing YouTube/Netflix — Transcode, CDN & Adaptive Bitrate, Traced and Designing YouTube or Netflix (System Design Problems). Mechanisms cross-referenced with What is CDN, Origin Server vs Edge Server, Push CDN vs Pull CDN, Introduction to Kafka (the transcode queue), and Storage Estimation for the BOTE.

🤖 Don't fully get this? Learn it with Claude

Stuck on Design YouTube / Netflix? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Design YouTube / Netflix** (Hands-On Builds) and want to truly understand it. Explain Design YouTube / Netflix from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Design YouTube / Netflix** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Design YouTube / Netflix** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Design YouTube / Netflix** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes