Designing YouTube: Upload, Transcoding Pipelines, and Adaptive Bitrate
A video platform is two systems wearing one product: a write path that is one of the largest batch-compute pipelines on earth (500 hours of video arrive every minute, each needing to become ~dozen encoded renditions), and a read path that is "just" static file serving — at a scale where it consumes double-digit percent of global internet traffic. The interview mistake is spending forty minutes on either half. The design skill is noticing they share almost nothing: different consistency needs, different scaling laws, different failure tolerance.
Requirements
Upload videos up to hours long; playable within minutes of upload; smooth playback across devices and network conditions; ~1B daily watch hours; a lost upload is unacceptable, a delayed one is fine.
Upload: resumable by contract
Multi-GB files over consumer connections will be interrupted, so upload is chunked and resumable (the same protocol shape as S3 multipart): client requests an upload session, sends chunks with offsets, finalizes. Chunks land directly in object storage via pre-signed URLs — video bytes should never transit your application servers. On finalize, the raw file is durable, a video row exists in state UPLOADED, and a message enters the processing queue. Everything after that is asynchronous — the user sees "processing," and the system owes them an eventual notification, not a response.
Transcoding: a DAG, not a job
The naive model — "run ffmpeg on the file" — fails the moment you ask how a 4-hour video becomes playable in minutes rather than after 8 hours of serial encoding. Production pipelines model processing as a DAG executed by a fleet:
probe -> split into segments (~2-10s at keyframes)
-> fan out: encode(segment × rendition matrix) <- the parallel middle
-> fan in: stitch manifests, generate thumbnails, captions,
content-ID fingerprint, moderation scan
-> publish (metadata flips to READY, CDN warm begins)
Split the video into segments, encode segments in parallel across hundreds of workers, then assemble. A 4-hour video becomes ~2,000 independent 10-second encode tasks; wall-clock time collapses from hours to minutes, bounded by the slowest segment. The rendition matrix (say 8 resolutions × 2-3 codecs) multiplies tasks again — one upload can be 30,000 tasks, which is why the scheduler is the real system: priority queues (new upload from a 50M-subscriber channel ≠ decade-old video re-encode), retry-with-idempotency per task (encoding is pure — same input segment, same output — so at-least-once execution is free), spot/preemptible instances for the bulk tier, and backpressure to admission.
Codec economics drive a second scheduling dimension: popular videos earn expensive encodes. Everything gets fast H.264; predicted-popular content gets VP9/AV1 passes that cost multiples of CPU but save 30-50% bandwidth forever after. Compute spent once versus bandwidth paid per view — a cost model worth saying out loud in the interview.
ABR: the client is the adaptive part
Adaptive bitrate is widely misunderstood as a server feature. In HLS/DASH, the server is dumb: it hosts small immutable segment files plus a manifest listing renditions and segment URLs. The player measures its own throughput and buffer, and picks which rendition's next segment to fetch:
buffer low + throughput dropping -> fetch 480p segment next
buffer full + throughput high -> step up to 1080p
All intelligence client-side, all content cacheable static files — the design reason HTTP-based streaming beat stateful protocols (RTMP) completely. Segment boundaries align across renditions (same keyframe cadence) so switching is seamless. Live streaming is the same machinery with a rolling manifest and a short DVR window; latency comes from segment duration × buffer depth, which is why low-latency modes shrink segments to ~1s chunks and pay for it in CDN request volume.
Read path: CDN with a popularity cliff
Views follow a brutal power law: a sliver of videos serve nearly all traffic. That makes the CDN story tiered by construction — hyper-popular content pinned in edge memory (including ISP-embedded caches; Google's OpenConnect-equivalent boxes inside carrier networks), the long tail served from regional origins on cache miss, and the cold tail living only in origin storage with lower-cost encoding. Metadata (titles, counts, comments) is the usual read-heavy cached-database problem and intentionally boring; view counting at this scale is the ad-click-aggregation problem — approximate live counters reconciled by batch, and nobody should promise exactness on the view counter.
| Interview probe | Answer sketch |
|---|---|
| Why is my video "processing"? | DAG mid-flight; publish flips atomically when the required rendition set completes — partial renditions can go live progressively (SD first, 4K later) |
| Encode worker dies mid-segment? | Idempotent pure task, re-queued; segment outputs content-addressed so duplicates collapse |
| First hour of a viral video? | Upload region encodes fast path; CDN fills on demand; predicted-hot content pre-warmed to edges |
| Storage math? | Raw + all renditions ≈ 2-3× raw; renditions are re-derivable from raw, so replicate raw hard, renditions cheaply |
The shape to remember: an ingest pipeline that is a distributed build system, and a delivery tier that is a static-file CDN with a popularity cliff — joined only by object storage and a metadata flip.
Keep reading
Write Skew: The Anomaly Snapshot Isolation Does Not Catch
Two transactions each read what the other writes, both commit, and an invariant dies. Snapshot isolation allows write skew — here is how to close the hole.
Designing a Shopping Cart: Price Snapshots, Merge, and No Inventory Hold
A cart is a per-user document, not a reservation. What to store on the line, how to merge an anonymous cart at login, and when the price is allowed to change.
Designing Snowflake-Style IDs: Ordering, Workers, and Clock Rollback
A 64-bit id from a timestamp, a worker number, and a per-millisecond sequence. How many you can issue, why the clock must not step backwards, and why JavaScript cannot hold one.
PostgreSQL 19 on October 29: WAIT for Read-Your-Writes, REPACK Without the Lock, and What Got Pulled
PostgreSQL 19 GA is scheduled for October 29, 2026. The WAIT command gives standbys read-your-writes, REPACK CONCURRENTLY replaces VACUUM FULL and CLUSTER, autovacuum goes parallel, and SQL/PGQ, online checksums, and FOR PORTION OF were reverted in Beta 4.
Idempotency Keys for Write APIs
How to make POST safe to retry: the key, the stored response, the race between two identical requests, and the expiry that forgets too soon.
Read-Your-Writes: The User Just Saved and the Read Replica Does Not Know
Why a write to the primary followed by a read from a replica shows stale data, and the practical ways to pin the next read without sending all traffic to the primary.
Newsletter
New posts, straight to your inbox
One email per post. No spam, no tracking pixels, unsubscribe anytime.
Comments
- No comments yet. Be the first.