Design YouTube: System Design & Architecture

Build a video platform: creators upload large video files, the system processes them into multiple qualities, and viewers around the world watch instantly at whatever quality their connection can handle.

Scope

In Scope

  • Upload: very large video files (hours long, tens of GB), uploaded reliably with resume support
  • Processing: transcoding each upload into multiple resolutions and formats, plus thumbnails
  • Playback: adaptive streaming worldwide - fast startup, seeking, and seamless quality switching as bandwidth changes
  • Video metadata: title, description, thumbnail, visibility (public / unlisted / private)
  • Engagement basics: view counting at scale, likes, and flat comments

Out of Scope

  • Search and discovery (a search-engine design of its own: indexing, ranking, autocomplete)
  • Recommendations and the home feed: personalized ranking is an ML system, and the subscriptions feed is the follow-graph fan-out problem already covered in Design a Newsfeed
  • Live streaming (real-time ingest and low-latency delivery change the architecture fundamentally)
  • Monetization, ads, and creator payouts
  • Content moderation and copyright matching (Content ID): policy pipelines worth their own design
  • Video editing tools, offline downloads, and background playback

💡 What is transcoding, and why can't we just serve the file the creator uploaded?

Transcoding is converting a video from one format into others: different resolutions (1080p, 720p, 480p, 360p), different compression settings, sometimes different codecs. We cannot serve the original upload for three reasons. First, the source is usually enormous - a camera or editing tool exports at high bitrate, often several GB per hour. Serving that to a phone on cellular data would buffer forever and burn the viewer's data plan for quality their screen cannot even show. Second, viewers' conditions vary wildly - fiber at home, spotty cellular on a train - and one file has exactly one quality. To adapt, we need the same video available at several quality levels, which is exactly what transcoding produces: a ladder of renditions. Third, devices disagree about formats. A codec a desktop browser plays natively may not decode on an older phone or a TV. Transcoding normalizes every upload into the formats the whole device ecosystem can play. So the deal is: the creator uploads one file, and the system spends compute once - up front - to turn it into many files, so that billions of playbacks later are cheap. That trade defines this whole design.

Functional Requirements

  • A creator can upload a large video reliably, resuming if the connection drops mid-upload
  • A creator can set the title, description, thumbnail, and visibility (public, unlisted, private)
  • A creator sees processing status, and the video becomes watchable at low quality quickly, with higher qualities appearing as they finish
  • A viewer can watch any video at a quality adapted to their connection, switching seamlessly when bandwidth changes
  • A viewer can seek to any point in a video without downloading everything before it
  • A viewer can like a video and leave a comment (flat - no reply nesting)
  • Views are counted and shown on the video; creators see their counts

Non-functional Requirements

  • Startup: first frame in under ~2 seconds globally; rebuffering (mid-playback stalls) under 1% of watch time
  • Processing: a standard upload is watchable (lowest rendition) within minutes; the full quality ladder completes within ~30 minutes
  • Read-heavy in the extreme: ~1,400 hours are watched for every hour uploaded (derived in the estimates)
  • Durability: an uploaded source file is never lost (11 nines, replicated object storage) - the creator may have no other copy
  • Availability: 99.99% for playback; under stress, degrade quality before ever failing playback
  • Scale: ~2B monthly users, ~1B hours watched/day, ~500 hours uploaded/minute

💡 What do "startup time" and "rebuffering" mean, and why do they rule the design?

Startup time is the gap between clicking play and seeing the first frame. It is dominated by a few round trips: fetch the manifest (the video's table of contents), then fetch the first segments of video. This is why players deliberately start at a conservative, lower quality - small first segments arrive fast, the video starts, and quality steps up once the player has measured your real bandwidth. That soft-looking first few seconds of a video is not a bug; it is the startup optimization working. Rebuffering is the mid-playback stall - the spinner - which happens when the player runs out of downloaded video before the network delivers more. Viewers forgive almost nothing less: measured watch time drops sharply with every stall, which is why "rebuffer ratio" is the metric streaming teams obsess over. Both metrics push the same direction: keep the video bytes as close to the viewer as possible (the CDN), chop video into small independently fetchable segments (so there is always a nearby next-chunk to grab), and let the client - which alone knows its own bandwidth and buffer - make the quality decisions. The server does not decide your quality; your player does. That division of labor is the heart of adaptive streaming.

Back-of-the-Envelope Estimates

  • Assume ~2B monthly active users, ~1B hours of video watched per day, ~500 hours of video uploaded per minute
  • A write is an upload, a transcode output, a metadata edit, or an engagement event (view, like, comment). A read is watching: manifest and segment fetches, plus metadata lookups
  • Uploads: 500 hours/min x 1,440 min = ~720K hours of new video per day
  • The ratio that defines the system: 1B hours watched ÷ 720K hours uploaded ≈ 1,400 hours watched per hour uploaded - the most read-heavy system in this practice set, and the reads are enormous objects, not rows
  • Views: 1B hours ÷ ~10 min average view ≈ 6B views/day ≈ 70K view events/sec average - view counting is its own firehose, separate from the bytes
  • Storage: at ~1.5GB per source hour, ~720K hours/day ≈ ~1PB/day of source; the rendition ladder roughly doubles the bytes, and replication multiplies again → roughly 5PB/day of growth, exabytes per year. The "exabyte scale" claim is derived, not asserted
  • Egress: 1B hours/day at ~1.5Mbps average ≈ 0.7GB/hour → ~700PB/day delivered ≈ 65Tbps average, spiking far higher. No origin infrastructure serves this - which is the proof that the CDN is not an optimization here, it IS the delivery system
  • Transcode compute: ~720K hours/day x ~5 renditions ≈ 3.6M encode-hours/day ≈ ~150K CPU cores busy around the clock, before peaks - the write path's real cost is compute, not disk

💡 What the estimates mean: storage is cheap, serving is everything

Three conclusions fall straight out of the numbers. First, the bytes-versus-metadata split from Design Dropbox, pushed to its extreme. Video bytes (exabytes, served at terabits per second) live in object storage and are delivered almost entirely by the CDN - the estimates show ~65Tbps average egress, which no database or app-server fleet could touch. Metadata (a few KB per video: title, status, counts) lives in a database and is cached hard. The two never mix, and the system is really two systems: a control plane that decides what plays, and a byte-delivery hierarchy that plays it. Second, popularity skew makes the CDN work. A tiny fraction of videos gets the overwhelming share of watches, so edge caches with a small fraction of total storage absorb 95%+ of requests. The long tail lives in cheaper, colder object storage where a slower first byte is acceptable - nobody notices 300 extra milliseconds on a video with twelve lifetime views. Tiering by popularity is how exabytes stay affordable. Third, the write path's cost is compute, not disk. ~150K cores of continuous transcoding dwarfs the cost of storing the output - which justifies the defining trade: transcode once, up front, into every quality we will ever serve, so that each of billions of playbacks is a dumb, cheap file read. The inverse choice (transcode on demand per viewer) would replace a one-time cost with a per-view cost - exactly backwards for a 1,400:1 read-to-write ratio. Where does that leave databases? Small and comfortable: video metadata is point-lookups by video_id (a document/KV store scales this trivially), comments follow the partition-by-video pattern from Design a Newsfeed, and view counts use the same buffered-counter trick as newsfeed likes. Nothing about the database tier here is exotic - all the exotic parts are in the pipeline and the CDN.

High-level Architecture

  • Upload Service: Manages resumable chunked uploads via presigned URLs (the Design Dropbox flow) - the source file lands directly in object storage, never passing through app servers
  • Processing Queue + Transcoding Fleet: A durable job queue feeding an elastic pool of workers; each upload fans out into one job per rendition, workers transcode and segment in parallel, and the fleet scales with queue depth
  • Object Storage: Source files and all renditions, stored as small streamable segments; tiered hot-to-cold by popularity
  • CDN: The delivery system - serves manifests and segments from edges worldwide, backed by an origin-shield cache tier that protects storage from miss storms
  • Metadata Service + Videos DB: Titles, descriptions, visibility, processing status, and denormalized counts - the control plane consulted at the start of every watch
  • Playback Service: Authorizes the viewer, returns the signed manifest URL, and gets out of the way - after this one call, everything is player and CDN
  • View/Engagement Pipeline: View events flow through a stream into buffered counters (the Design a Newsfeed pattern), with fraud filtering before anything counts
  • Comments (NoSQL, partitioned by video): flat comments, exactly the newsfeed comment model

Data/User Flow Diagram

UPLOAD + PROCESS - the write path (compute-heavy, runs once)
[Creator] --init--> [Upload Service] --> [Videos DB: status=uploading]
    |  presigned chunk URLs (resumable - the Design Dropbox flow)
    v
[Object Storage: source file]
    |  upload complete -> enqueue
    v
[Processing Queue] --> [Transcoding Fleet (elastic)]
                          |  fan-out: one job per rendition
                          |  1080p | 720p | 480p | 360p + thumbnails
                          v
              [Object Storage: renditions, chopped into
               4-10s segments] --> write manifest
                          |
                          v
              [Videos DB: status=ready]  (low rendition publishes
                                          first; ladder fills in)

WATCH - the read path (runs billions of times, must be dumb-cheap)
[Viewer] --> [Playback Service] --> [Videos DB] visibility check
    |            returns signed manifest URL
    v
[CDN edge] --(miss)--> [Origin shield] --(miss)--> [Object Storage]
    |
    |  player: reads manifest -> starts at conservative quality ->
    |  measures bandwidth + buffer each segment -> steps up/down
    v
[View events] --> [Event stream] --> [fraud filter] -->
                  [buffered counters] --> [Videos DB counts]

💡 What is a manifest, and how does adaptive streaming actually work?

Every processed video is chopped into small segments - 4 to 10 seconds of video each - and each rendition (1080p, 720p, 480p...) is its own parallel set of segments. The manifest (an HLS or DASH playlist file) is the table of contents: it lists the available renditions with their bitrates, and where every segment of each rendition lives. Playback is then a loop the player runs entirely on its own: fetch the manifest, start with a conservative rendition so the first frame arrives fast, and then, before each next segment, look at two numbers - how fast recent segments downloaded, and how many seconds of video are sitting in the buffer. Bandwidth comfortably above the next rendition's bitrate and a healthy buffer? Step up. Downloads falling behind playback? Step down before the buffer runs dry. Because all renditions are cut at the same time boundaries, swapping quality between segments is invisible - no gap, no restart. Seeking works the same way: jumping to minute 43 means fetching the segment covering minute 43, not anything before it. Notice who is in charge: the server never picks your quality. Only your player knows your bandwidth and buffer this second, so the intelligence lives at the edge of the network, in the client - and the server side stays a dumb, cacheable file store, which is exactly what lets a CDN serve it at planetary scale.

Data Model & Storage

  • Videos (NoSQL document/KV store, keyed by video_id): title, description, channel_id, visibility, processing status, duration, thumbnail refs, denormalized view/like/comment counts, and the rendition table (which qualities exist, their manifest key). Access is point-lookup by id plus by-channel listings - a KV/document shape, no joins needed.
  • Channels/Users (PostgreSQL): account identity, channel names - small, relational, constraint-friendly.
  • Source + Renditions (Object Storage): the actual bytes. One source file per video plus each rendition as thousands of small segment files, tiered by popularity: hot content replicated near edges, the long tail in colder, cheaper storage classes.
  • Manifests (Object Storage, served via CDN): one small text file per video listing renditions and segments - the highest-request-rate object per video, cached everywhere.
  • Processing Jobs (durable queue + status rows): one job per rendition per video, with retry counts and a dead-letter queue for poison files.
  • View events (stream, short retention): the raw 70K events/sec firehose, aggregated into buffered counters and dropped - raw events are not kept long-term.
  • Comments (NoSQL, partitioned by video_id, sorted by time): flat rows - the Design a Newsfeed comment model verbatim. Likes: one row per (video, user), idempotent, with buffered denormalized counts.

💡 Why we deliberately store the same video five times (the anti-Dropbox move)

Design Dropbox goes to great lengths to store identical bytes exactly once - block-level dedup, content hashes, reference counts. This design does the opposite on purpose: every video is stored as five-plus renditions, multiplying the bytes several-fold. Both are right, and the difference is which resource dominates each system's cost. For Dropbox, storage is the product: files sit for years and are rarely read, so bytes-at-rest dominate cost and dedup pays directly. For YouTube, serving is the product: the 1,400:1 watch-to-upload ratio means each video's bytes are read astronomically more often than written, so the cost that matters is per-playback. Pre-computing every rendition makes each playback a dumb file read from a cache. The alternative - transcoding on demand for each viewer's bandwidth - would attach a compute cost to every single view, which at billions of views a day is the most expensive possible place to spend. Same logic tiered the other direction: the long tail (most videos, few views) can afford a shorter ladder - some platforms skip generating the top renditions until a video shows traction, spending transcode compute only where playbacks will amortize it. The interview-worthy sentence: dedup and deliberate duplication are the same decision - minimize the dominant cost - made in systems whose dominant costs are opposites.

API Design

POST /v1/videos
Create the video record (metadata) and initialize a resumable upload; returns presigned chunk URLs. Accepts an Idempotency-Key.
POST /v1/videos/:id/upload-complete
All chunks uploaded; validates and enqueues processing.
GET /v1/videos/:id
Metadata, processing status, available renditions, counts.
GET /v1/videos/:id/watch
Authorize the viewer and return the signed manifest URL - the one control-plane call per playback.
PUT /v1/videos/:id
Edit metadata, thumbnail, visibility.
POST /v1/videos/:id/view-events
Playback beacons (started, progress, finished) feeding the counting pipeline.
POST /v1/videos/:id/likes
Like/unlike; idempotent per user.
POST /v1/videos/:id/comments
Add a flat comment (GET to read, cursor-paginated).

Low-level Design

Upload Service - getting tens of GB in reliably (step by step):

  • 1) POST /v1/videos with metadata and file size creates the video row (status=uploading) and returns presigned URLs for ~10MB chunks - the same direct-to-storage, resumable pattern as Design Dropbox, so a dropped connection at 90% resumes from chunk 900, not zero.
  • 2) The client uploads chunks in parallel straight to object storage; our servers never touch the bytes.
  • 3) upload-complete verifies all chunks, assembles the source object, and enqueues processing.
  • 4) The creator immediately gets their watch URL - it shows "processing" until the first rendition lands.
  • One notable non-feature: no cross-user dedup. Unlike Dropbox, virtually every source upload is unique footage, so content-hash dedup would find almost nothing - knowing when a pattern does NOT apply is part of knowing the pattern.

Processing pipeline - one file becomes many (the genuinely tricky part):

  • 1) Probe the source: duration, resolution, codec - and reject or quarantine files that lie about their type.
  • 2) Build the rendition ladder from the source: a 1080p upload gets 1080p/720p/480p/360p; a 480p upload gets only 480p/360p - never upscale, it spends compute to add zero information.
  • 3) Fan out one job per rendition onto the queue; independent workers transcode in parallel. Long videos parallelize twice: the file is split into time ranges, each range transcoded on a different worker, and the results stitched - this is how a 3-hour video is ready in minutes, not hours.
  • 4) Each worker writes its rendition as 4-10s segments plus updates the manifest; thumbnails are generated alongside.
  • 5) Publish progressively: the moment 360p finishes, the video flips to ready and is watchable; higher qualities appear in the manifest as they land. This is why a just-uploaded video sometimes offers only low quality for a few minutes - the ladder is still filling in.
  • 6) Failures retry per-rendition (one bad job never re-runs the others); poison files go to a dead-letter queue for inspection.
  • 7) The fleet is elastic on queue depth - upload volume swings hard, and idle transcoders are pure waste.

Playback Service - the one smart call, then get out of the way:

  • 1) GET /v1/videos/:id/watch checks visibility (public/unlisted/private) and returns a short-lived signed manifest URL.
  • 2) Everything after is player-and-CDN: manifest fetch, conservative first rendition for fast startup, then the adapt-per-segment loop from the architecture note.
  • 3) Private and unlisted videos stay protected at the edge: the CDN validates the URL signature before serving any segment, so a shared link dies when the signature expires - the same signed-URL enforcement as Design Dropbox downloads.
  • 4) Seeks fetch the target segment directly; nothing before it is downloaded.
  • The design goal in one line: after one authorization call, serving a billion-view video and a twelve-view video is the same dumb file-serving loop.

CDN and tiered storage - respecting the popularity skew:

  • A tiny fraction of videos produces most watches, so edges holding a sliver of total bytes absorb 95%+ of requests.
  • Misses do not go straight to storage: an origin shield (regional cache tier) sits between, and request coalescing collapses a thousand concurrent misses for one hot segment into a single origin fetch - without it, a video going viral would stampede storage with identical requests.
  • Rising velocity pre-warms edges with the new hot segments before the peak hits.
  • The cold tail settles into cheaper storage classes where first-byte latency is slower and nobody notices - a video with twelve lifetime views does not earn edge real estate.
  • Bytes tier by temperature; the manifest stays hot everywhere because every playback starts with it.

View counting - 6B views/day without melting anything:

  • 1) Players send lightweight beacons (started, progress, finished).
  • 2) Beacons flow into an event stream, not the database - 70K/sec average would be a hot-row bloodbath as direct increments on viral videos.
  • 3) Fraud filtering runs before counting: bot swarms, replay loops, and view-farm patterns are dropped here. Counts feed monetization eventually, so inflated views are a financial attack, not a vanity problem - this is why real platforms audit and sometimes freeze counts mid-viral (the famous 301+ behavior of early YouTube).
  • 4) Aggregators buffer per-video counts and flush every few seconds - the exact buffered-counter pattern from Design a Newsfeed likes, one order of magnitude hotter.
  • 5) Displayed counts are approximate in real time, reconciled to exact in batch. Watch-time analytics for creators ride the same stream into an analytics store, separate from the serving path.

Comments and likes - imported patterns, nothing new:

  • Comments: flat rows partitioned by video_id, cursor-paginated, newest or top first - the Design a Newsfeed comment model verbatim, and deliberately flat since threading was de-scoped there for the same reason.
  • Likes: one row per (video, user) so liking is idempotent, with the count denormalized onto the video row via the same buffered flush as views.
  • The lesson in the brevity: once a sub-pattern is solved in one design, recognize it and import it - interviews reward "this is the newsfeed comment pattern" far more than re-deriving it slowly.

Database Types and Schemas

Storage layout & schemas

- Videos (NoSQL document store, keyed by video_id)
  {
    "video_id": "v_8f3e2d1c",
    "channel_id": "ch_42",
    "title": "...", "description": "...",
    "visibility": "public",            -- public | unlisted | private
    "status": "ready",                 -- uploading | processing | ready | failed
    "duration_seconds": 1260,
    "thumbnail_ref": "thumbs/v_8f3e2d1c/1.jpg",
    "manifest_key": "manifests/v_8f3e2d1c/master.m3u8",
    "renditions": [                    -- fills in progressively
      { "quality": "360p",  "bitrate_kbps": 500,  "ready": true },
      { "quality": "720p",  "bitrate_kbps": 1800, "ready": true },
      { "quality": "1080p", "bitrate_kbps": 3500, "ready": false }
    ],
    "view_count": 182304,              -- denormalized, buffered-flush updated
    "like_count": 8921,
    "comment_count": 412,
    "uploaded_at": "2026-07-05T18:04:11Z"
  }
  -- access pattern: point lookup by video_id (every watch), list by channel

- Object Storage layout (the bytes; tiered hot -> cold by popularity)
  /source/{video_id}/original.mp4          -- the upload, never deleted
  /renditions/{video_id}/{quality}/seg_00001.ts   -- 4-10s segments
  /manifests/{video_id}/master.m3u8        -- the table of contents
  /thumbs/{video_id}/{n}.jpg

- Processing Jobs (durable queue + status)
  job_id, video_id, rendition ('720p'), time_range (for split long videos),
  status (queued|running|done|failed), attempts, last_error
  -- one job per rendition (x time-range); retries are per-job;
  -- repeated failures land in a dead-letter queue

- Comments (NoSQL, the Newsfeed pattern)
  PK: video_id, SK: ts#comment_id
  Attributes: user_id, text, like_count
  -- flat by design; nesting was de-scoped for the same reasons as Newsfeed

- Likes (NoSQL)
  PK: video_id, SK: user_id  -- one row = idempotent like
  GSI: user_id -> videos this user liked

Redis / stream keys

- View-count buffers (the Newsfeed counter pattern, hotter)
  "views:{video_id}" -> pending increments, flushed every few seconds

- Hot metadata cache
  "video:{video_id}" -> rendered metadata JSON, TTL ~60s

- View event stream (Kafka-style, short retention)
  topic: view-events, partitioned by video_id
  consumers: fraud filter -> counter aggregator -> analytics sink

API Request/Response Payloads

POST /v1/videos (init upload)
Request
{
  "title": "Building a Cabin in 30 Days",
  "description": "Full timelapse and walkthrough",
  "file_size": 8589934592,
  "content_type": "video/mp4",
  "visibility": "public"
}
Response
{
  "video_id": "v_8f3e2d1c",
  "upload_session_id": "up_7a2b8f4e",
  "chunk_size": 10485760,
  "chunk_count": 819,
  "upload_urls": [
    { "chunk_number": 1,
      "presigned_url": "https://storage.example.com/source/...(signed)",
      "expires_at": "2026-07-05T20:04:11Z" }
  ],
  "parallel_uploads": 4
}

// Resumable: chunks upload in parallel, straight to object storage; a
// dropped connection re-requests URLs only for missing chunks - the
// Design Dropbox upload flow, minus the dedup (every video's bytes are
// effectively unique, so content-hash dedup would find nothing).
GET /v1/videos/:id (processing in progress)
Response
{
  "video_id": "v_8f3e2d1c",
  "status": "processing",
  "watchable": true,
  "renditions": [
    { "quality": "360p", "ready": true },
    { "quality": "720p", "ready": true },
    { "quality": "1080p", "ready": false, "eta_minutes": 12 }
  ],
  "view_count": 3,
  "uploaded_at": "2026-07-05T18:04:11Z"
}

// Progressive publishing: the video went live the moment 360p finished.
// Higher qualities join the manifest as their transcode jobs complete -
// which is why fresh uploads sometimes max out at 360p for a few minutes.
GET /v1/videos/:id/watch
Response
{
  "video_id": "v_8f3e2d1c",
  "manifest_url": "https://cdn.example.com/manifests/v_8f3e2d1c/master.m3u8?sig=...&exp=1751911451",
  "duration_seconds": 1260,
  "thumbnail_url": "https://cdn.example.com/thumbs/v_8f3e2d1c/1.jpg"
}

// The only control-plane call in a playback. The manifest URL is signed
// and short-lived; the CDN validates the signature on every segment
// request, so private/unlisted videos stay protected even at the edge.
// From here on, it is entirely player <-> CDN.
What the player fetches next (the manifest, abridged)
Response
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=500000,RESOLUTION=640x360
360p/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1800000,RESOLUTION=1280x720
720p/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=3500000,RESOLUTION=1920x1080
1080p/playlist.m3u8

// The table of contents: one line per rendition with its bitrate. The
// player starts low (fast first frame), measures how quickly segments
// arrive, and steps up or down the ladder between segments. The server
// never chooses the quality - the client does.
POST /v1/videos/:id/view-events
Request
{
  "event": "progress",
  "session_id": "ps_9d4f1a2b",
  "position_seconds": 300,
  "watched_seconds": 290
}
Response
{
  "ok": true
}

// Beacons feed the stream -> fraud filter -> buffered counters, never
// the database directly. Displayed counts are approximate in real time
// and reconciled in batch - the Newsfeed like-counter pattern at 6B
// events/day. Fraud filtering runs BEFORE counting: view counts
// eventually feed monetization, so inflation is a financial attack.

💡 Three terms from the flows: rendition ladder, segment alignment, origin shield

Rendition ladder: the ordered set of qualities a video is available in (360p → 720p → 1080p...), each rung a complete, independently playable copy at a different bitrate. Built once at upload; every playback climbs and descends it freely. Never taller than the source - upscaling spends compute to add zero information. Segment alignment: all renditions are cut at the same time boundaries, so segment 47 covers the same seconds of video in every quality. That is the property that makes quality switching seamless - the player finishes segment 47 at 720p and starts segment 48 at 480p with no gap, no overlap, no decoder restart. Without alignment, adaptive streaming would stutter at every switch. Origin shield: a cache tier between the CDN edges and object storage. When a video goes viral, thousands of edges miss the same new segment at once; the shield absorbs those misses, and request coalescing turns the thousand identical fetches into one trip to storage. Edges protect the shield, the shield protects storage - the same "each layer absorbs its multiplier" logic as the whole read path.

Concluding Discussion

Potential Bottlenecks

  • Issue: A video goes viral and thousands of CDN edges miss the same segments simultaneously, threatening a stampede on storage.
    Mitigation: origin shield plus request coalescing (a thousand concurrent identical misses become one origin fetch), and velocity-triggered pre-warming pushes rising content to edges before the peak.
  • Issue: Upload spikes (breaking news, trending challenges) back up the transcode queue and delay publishing.
    Mitigation: the worker fleet is elastic on queue depth, jobs are per-rendition so they parallelize freely, and progressive publishing means creators are live at 360p in minutes even while the ladder backlog drains.
  • Issue: Viral-video view counts are a hot-key firehose (thousands of increments/sec on one row).
    Mitigation: stream aggregation with buffered flushes - the Newsfeed counter pattern - with exact reconciliation in batch.

Single Points of Failure

  • The processing queue: if it dies, publishing stops - but nothing is lost, because every source file is already durable in object storage; jobs re-enqueue on recovery. Run it clustered; the failure mode is delay, not loss.
  • The metadata DB: every watch starts with one lookup here. Cache metadata hard (it changes rarely) and run replicas - with warm caches, playback of popular content continues even through a database failover.
  • The CDN itself: a single-provider outage takes delivery down worldwide. Serious video platforms run multi-CDN with health-based traffic steering; manifests make this invisible (same segment paths, different hostnames).

Security Improvements

  • Signed, expiring URLs on manifests AND segments, validated at the CDN edge - private and unlisted videos stay private even though they are served from a public cache network (the Design Dropbox signed-download pattern).
  • Validate uploads before processing: probe the real container/codec (a "video" that is not one never reaches the transcoder fleet), and scan for malware - transcode workers handle hostile input by design, so they run sandboxed with no network access.
  • Fraud-filter view events before counting: counts feed monetization, so view inflation is a financial attack; filter, audit, and reconcile.
  • Takedowns must be edge-aware: tombstone the metadata AND purge/invalidate CDN copies, or the "deleted" video keeps playing from caches for hours.

Critical Knowledge

If the interviewer asks "why store five copies of every video instead of transcoding on demand?":

  • Follow the dominant cost. The watch-to-upload ratio is ~1,400:1, so per-playback cost dwarfs at-rest cost: pre-transcoding turns every playback into a dumb cached file read, while on-demand transcoding would attach compute to every one of billions of daily views - the most expensive possible place to spend.
  • Name the inversion: Design Dropbox dedups because its dominant cost is bytes at rest; YouTube deliberately multiplies bytes because its dominant cost is serving. Same principle - minimize what dominates - opposite conclusions.
  • Show the nuance: the long tail flips the math back, so platforms often build short ladders for cold videos and add top renditions only when traction shows.

If the interviewer asks "what happens when my connection gets slow mid-video?":

  • Walk the loop: video is pre-cut into 4-10s segments per rendition; before each fetch the player checks measured throughput and buffer depth; falling behind → step down a rung, comfortably ahead → step up.
  • The switch is invisible because renditions are cut at aligned time boundaries - segment 48 at 480p picks up exactly where segment 47 at 720p ended.
  • Emphasize who decides: the client, not the server - only the player knows its own bandwidth and buffer this second, and pushing the intelligence to the edge keeps the server a dumb cacheable file store.
  • Startup is the same trick at t=0: begin conservative for a fast first frame, upgrade once real bandwidth is measured - the soft first seconds are the optimization working.

If the interviewer asks "how is a 3-hour video ready to watch in minutes?":

  • Parallelism in two dimensions plus honest sequencing. Fan out across the ladder: each rendition is an independent job on a separate worker.
  • Fan out across time: split the source into ranges, transcode ranges concurrently, stitch - a 3-hour file becomes dozens of parallel ten-minute jobs.
  • Publish progressively: go live the instant the lowest rendition lands; the ladder fills in behind.
  • Close with the ops reality: the fleet is elastic on queue depth (~150K cores at steady state from the estimates), jobs retry per-rendition, and poison files go to a dead-letter queue instead of wedging the pipeline.

If the interviewer asks "why is the view count approximate?":

  • Because 6B views/day (~70K/sec) as direct database increments would make every viral video a hot-row disaster - so beacons flow through a stream into buffered per-video counters flushed every few seconds, the Design a Newsfeed like-counter pattern an order of magnitude hotter.
  • The second, less obvious reason: correctness here means fraud-filtered, not just summed - counts feed monetization, so bot swarms and replay loops must be dropped before counting; that filtering is why counts on real platforms sometimes freeze mid-viral.
  • Approximate-now, exact-later: reconciliation in batch trues everything up.
  • The judgment line: sub-second exactness on a vanity metric is not worth a hot key - but financial-grade auditing of the same number is worth a pipeline.

If the interviewer asks "what does the CDN do versus what do your servers do?":

  • Split the system in two: a control plane (authorize, look up metadata, hand out a signed manifest URL - one small call per playback) and a byte plane (manifests and segments, ~700PB/day, served ~95%+ from CDN edges).
  • Do the disproof by numbers: ~65Tbps average egress is beyond any origin fleet - the CDN is not accelerating delivery, it IS delivery; our storage is merely the cache-fill source.
  • Explain why caching works at all: popularity skew - a sliver of videos is most of the watches, so edges holding a fraction of bytes absorb nearly all requests, while the tail rests in cold storage where slow first-byte hurts nobody.
  • This is Design Dropbox's bytes-versus-metadata split at its logical extreme: the metadata tier is boring on purpose; every exotic thing in this design lives in the pipeline and the cache hierarchy.