Skip to content
System Design

Learn

Design YouTube

Designing YouTube: chunked uploads, the transcoding pipeline as a DAG, adaptive bitrate streaming with HLS/DASH, CDN strategy, and view-count aggregation at scale.

3 min readUpdated 2 Sept 2026

#Video#Transcoding#CDN#Streaming

A video platform is two loosely coupled systems: a heavy asynchronous **upload and transcode pipeline, and a read path that is essentially a CDN with a database attached**. Keep them separate in your answer and the design stays clean.

Requirements

Functional

  • Upload a video; watch a video.
  • Search, recommendations, view counts, comments and likes.

Non-functional

  • Playback starts in under a couple of seconds and does not buffer.
  • Upload may take minutes and processing may take longer — that is acceptable and should be

asynchronous.

  • Extremely read-heavy, and extremely bandwidth-heavy.
500 hours of video uploaded per minute
1B hours watched per day
Storage: 500 h/min × 60 × 24 = 720,000 h/day
         ~1 GB/hour raw, ×5 for multiple encodings ≈ 3.6 PB/day
Bandwidth dominates every other cost in this system.

That last line is the point: **the CDN bill, not the servers, is what this design is optimising.**

Upload

Never a single HTTP POST — a dropped connection at 95% of a 4 GB file must not restart.

1. Client asks for an upload URL; metadata row created as status=UPLOADING
2. Client uploads in chunks (5-10 MB) DIRECTLY to blob storage via a
   presigned URL — the application servers never touch the bytes
3. Each chunk is retried independently; the client can resume
4. Storage fires a completion event → enqueue a transcoding job

Uploading straight to blob storage is the detail to volunteer: routing petabytes through your own servers would be both a bandwidth cost and a scaling ceiling for no benefit.

Transcoding

The heart of the system. One source file becomes many renditions, and the work is a

DAG of independent tasks so it parallelises:

                    ┌→ 1080p ┐
raw → split into    ├→  720p ├→ segment into 4-10s chunks → package (HLS/DASH) → CDN
      GOP segments  ├→  480p │
                    └→  240p ┘
                    ├→ thumbnails
                    └→ audio tracks, captions (ASR)

Two things make this fast. Split the source first — segment the video and transcode segments in parallel across many workers, so a two-hour film is not one serial job. And fan out the renditions — each resolution is independent work.

Jobs go through a queue with retries and a dead-letter queue; workers are stateless and autoscaled, ideally on spot instances since the work is interruptible. Publish the video as soon as the first (lowest) rendition is ready, and add higher qualities as they finish.

Adaptive bitrate streaming

The client does not download a file; it fetches a manifest listing renditions and segments, then requests segments one at a time, switching quality as measured bandwidth changes.

master.m3u8
  ├─ 240p/playlist.m3u8  → seg0.ts, seg1.ts, …
  ├─ 480p/playlist.m3u8
  ├─ 720p/playlist.m3u8
  └─ 1080p/playlist.m3u8
sourceone uploadmanifest1080p720p480p240phighlighted = the segments one player actually fetched
The player fetches segments one at a time and changes rendition as bandwidth moves — so a slow connection degrades quality instead of buffering.

HLS (Apple) and MPEG-DASH (standard) are the two protocols. The consequences to mention: playback starts fast because only the first segment is needed; a bandwidth drop degrades quality instead of buffering; and segments are static files, so **everything is CDN-cacheable**.

Serving

Client → nearest CDN edge
           hit  → serve (this is the overwhelming majority)
           miss → origin blob storage → cache → serve

Popularity is extremely long-tailed: a small fraction of videos is most of the traffic. Push popular content to edges proactively, and let the tail be pulled on demand. Regional caching matters too — a video trending in one country need not be resident everywhere.

Metadata and view counts

videos     video_id, uploader_id, title, description, duration,
           status, created_at, manifest_url, thumbnail_url
views      aggregated separately — NOT a counter on the video row

Incrementing a row per view would make a viral video's row a write hotspot and put database writes on the playback path. Instead, emit a view event to Kafka, aggregate in a stream processor, and write periodic rollups. Exact real-time counts are not required — YouTube famously freezes counts near 300 while verifying, which is a good example to cite of choosing throughput over immediate accuracy.

Follow-ups to expect

  • Search — a separate inverted index over title, description, captions and transcripts.
  • Recommendations — candidate generation from watch history and collaborative filtering,

then a ranking model; precomputed per user, refreshed periodically.

  • Live streaming — the same pipeline with much shorter segments and low-latency HLS;

the trade-off is latency versus resilience.

  • Copyright matching — perceptual fingerprints of audio and video compared against a

reference database at upload.

  • Resumable upload state — track received chunks so a resumed upload skips them.
  • Cost — storing five renditions of everything forever is expensive; delete unwatched

high-resolution renditions of cold videos and re-encode on demand.

Track this problem on the System Design sheet.

Frequently asked

How does video transcoding scale on a platform like YouTube?

By splitting the source into segments and transcoding them in parallel across many stateless workers, and by treating each output resolution as an independent task — the whole thing is a DAG of small jobs pulled from a queue. Publishing as soon as the lowest rendition is ready means the video goes live long before every quality is finished.

What is adaptive bitrate streaming?

The video is encoded at several qualities and cut into short segments, with a manifest listing them. The player requests segments one at a time and switches rendition as measured bandwidth changes, so a slow connection degrades quality instead of buffering. Because segments are static files, HLS and DASH streams are fully CDN-cacheable.

How are view counts handled at scale?

Not as a counter on the video row — that would put a database write on the playback path and make a viral video's row a hotspot. Views are emitted as events to a stream, aggregated by a stream processor, and written back as periodic rollups. The count is eventually consistent, which is an acceptable trade for the throughput.

Related