system-design

Design a Video Streaming Service (YouTube / Netflix)

Difficulty: Tier 3 Asked at: Google/YouTube, Netflix, Amazon, Careem (for their media) Time budget: 45–60 min

Video is the heaviest payload in system design: a single movie is gigabytes, watched by millions simultaneously, on every network condition from fiber to 3G. The two big ideas are transcoding (turn one upload into a ladder of resolutions/bitrates) and adaptive bitrate streaming over a CDN (the player picks the quality that fits the current network). Get those two and you’ve got it.

Prerequisites: Object Storage, CDN, Message Queues


1. Requirements

Functional:

Non-functional:

Out of scope: the recommendation model (separate), DRM internals (mention), live streaming (a variant — mention the difference).


2. Estimation


3. The two pipelines

Split cleanly into upload/processing (write, rare, heavy compute) and streaming (read, constant, bandwidth-heavy).

Upload & transcoding pipeline

flowchart LR
    Creator -->|pre-signed upload| S3[(Object Storage<br/>original)]
    S3 -->|event| Q[[Transcoding queue]]
    Q --> W[Transcoding workers]
    W -->|split into segments,<br/>encode ladder| Variants[(Object Storage<br/>HLS/DASH segments<br/>240p...4K)]
    W --> Meta[(Video metadata:<br/>ready, manifest URL)]
    Variants --> CDN[CDN]
  1. Creator uploads the original directly to object storage (pre-signed URL).
  2. Upload triggers a transcoding job. Workers split the video into short segments (e.g. 2–10 s) and encode each into a ladder of resolutions/bitrates (240p → 4K) and formats, producing HLS/DASH segments + a manifest listing the available renditions.
  3. Segments land in object storage, distributed to the CDN. Metadata marks the video ready.

🚨 Transcoding is async, segmented, and parallel — you can encode different segments/renditions concurrently across a worker fleet, so a long video processes fast.

Streaming pipeline (adaptive bitrate)

flowchart LR
    Player -->|1. get manifest| API[API]
    Player -->|2. fetch segments| CDN[CDN edge]
    CDN -.miss.-> Origin[(Object Storage)]
    Player -->|3. measure bandwidth,<br/>pick rendition per segment| Player

The player downloads the manifest, then requests video segment by segment, choosing the rendition (quality) that fits the currently measured bandwidth. Network dips → next segment at lower quality (no rebuffer); network recovers → higher quality. This is Adaptive Bitrate Streaming (ABR).


4. Deep dives

4a. Why segment + ABR?

🚨 The core idea. A single fixed-quality file either buffers on slow networks or looks bad on fast ones. Segmenting the video and offering each segment in multiple bitrates lets the player adapt mid-playback, per segment, to the real-time network — smooth playback everywhere. Segments are also CDN-cache-friendly (small, immutable, reusable across viewers).

4b. CDN is the whole ballgame for serving

Terabits/sec cannot come from your origin. Popular videos’ segments are cached at CDN edges worldwide; viewers stream from the nearest edge. Origin (object storage) is hit only on cache miss (cold/long-tail content). 🚨 CDN offload + segment immutability is what makes global streaming economically possible. (CDN) Netflix even places caches (Open Connect) inside ISPs.

4c. Storage tiering

Petabytes, but access is very skewed — a few videos are watched constantly, the long tail rarely. Tier storage: hot content on fast storage/CDN, cold content on cheap cold storage. Keep only popular renditions hot; re-encode/rehydrate cold ones on demand.

4d. Handling the transcoding fleet

Transcoding is CPU/GPU-heavy. A queue buffers upload spikes; an autoscaling worker fleet drains it. Prioritize (a popular creator’s video first). Failures retry per segment. This is a classic background-job / batch system.

4e. Live streaming (if asked)

Live is the same segmenting/ABR idea but real-time: ingest → transcode segments on the fly → push to CDN with a few seconds of latency. The difference is you can’t pre-process; you trade a small delay for liveness. Mention, don’t rabbit-hole.

4f. View counts

Billions of views → a hot-counter problem. Don’t increment a row per view: aggregate view events through a stream (ad-click aggregator pattern) into approximate counts. Deduplicate to avoid inflating counts.


5. Bottlenecks & scaling further

  1. Serving bandwidth → CDN, edge caches in ISPs, segment caching.
  2. Storage growth → tiering hot/cold; keep popular renditions hot.
  3. Transcoding compute → autoscaling GPU/CPU worker fleet + queue.
  4. Startup latency → pre-warm popular content to edges; small initial segments.
  5. View-count hotspots → stream aggregation, approximate counters.

6. Trade-off summary

Decision Chosen Alternative Why
Playback Adaptive bitrate (segmented) Single fixed file Smooth on any network; no rebuffer
Serving CDN edge caches Origin serving Terabits/sec is only feasible from the edge
Transcoding Async, segmented, parallel Sync on upload Long videos process fast; upload returns instantly
Storage Hot/cold tiering All hot Access is skewed; cold storage is far cheaper
View counts Stream-aggregated, approximate Exact per-view increment Avoids hot-counter contention

7. Follow-up questions

What is adaptive bitrate streaming and why is it essential? Adaptive bitrate streaming (ABR) splits a video into short segments (a few seconds each) and encodes each segment at multiple quality levels (bitrates/resolutions), with a manifest listing what's available. The player downloads segment by segment, continuously measuring the available bandwidth, and picks the highest quality that will download in time for each segment — dropping to a lower bitrate when the network slows and climbing back up when it recovers. It's essential because network conditions vary wildly and change mid- playback: a single fixed-quality file would either buffer constantly on slow connections or waste bandwidth and look unnecessarily low-res on fast ones. ABR gives smooth, uninterrupted playback across all conditions, and because segments are small and immutable they cache extremely well at CDN edges and are reused across viewers.
Why can't you serve video from your own servers/origin? Because the bandwidth is astronomical — billions of watch-hours a day is on the order of terabits per second sustained, globally. No practical origin cluster can emit that, and even if it could, serving every viewer from a central location would mean terrible latency and buffering for anyone far away. A CDN solves both: video segments are cached at thousands of edge locations near users, so the vast majority of bytes are served from a nearby edge, and your origin (object storage) is touched only on cache misses for cold, long- tail content. Because segments are immutable, edge caching is clean (no invalidation). Providers like Netflix go further and place caching appliances inside ISP networks. CDN offload isn't an optimization here — it's what makes the service physically and economically possible.
Walk through what happens from upload to first playable. The creator uploads the original file directly to object storage via a pre-signed URL, so the bytes never touch your app servers, and the upload returns immediately. That upload emits an event onto a transcoding queue. A fleet of workers picks it up, splits the video into short segments, and encodes each segment into a ladder of resolutions and bitrates plus the required streaming formats (HLS/DASH), producing a manifest that lists all the renditions. These segments are written back to object storage and propagated to the CDN, and the video's metadata is flipped to "ready" with the manifest URL. Because segments and renditions are independent, workers encode them in parallel, so even a long video becomes watchable quickly. When a viewer opens it, the player fetches the manifest and then streams segments from the nearest CDN edge, choosing quality adaptively.
Storage is petabytes but most videos are rarely watched. How do you manage cost? Exploit the heavily skewed access pattern with storage tiering. A small set of popular videos accounts for most views, so keep those — and only their commonly-watched renditions — on fast storage and hot in the CDN. The long tail of rarely-watched content lives in cheap cold storage, and you can even keep fewer renditions for it, re-encoding or rehydrating on demand if someone does watch. This matches spend to access: you pay for fast storage only where it earns its keep, and cold storage (much cheaper per byte) absorbs the bulk of the petabytes that are seldom touched.

8. What junior / mid / senior answers look like


Further reading