Design YouTube
The interviewer asks
“Design YouTube: creators upload videos of any length, the platform processes them, and billions of viewers around the world watch them smoothly on any device and network. Cover upload, processing, playback and view counts.”
What a strong answer looks like
A strong answer splits YouTube into a write path and a read path with very different shapes. The write path is a resumable upload to object storage followed by an asynchronous processing pipeline: split the video into chunks, transcode them in parallel into a bitrate ladder (144p to 4K, H.264 plus VP9/AV1), package as HLS/DASH segments, run moderation, and publish. The read path is dominated by bandwidth: ~100 Tbps of video served almost entirely from CDN and ISP-embedded caches using adaptive bitrate streaming, while the origin serves only metadata, manifests and cache misses. Metadata lives in sharded MySQL (YouTube built Vitess for exactly this) with heavy caching, and view counts are aggregated in streams rather than incremented per view. The deep dives are the transcoding pipeline, ABR plus CDN tiering, metadata scaling, and view counting.
Concepts to mention
1 Requirements
Functional
- Creators upload videos (up to 12 hours / 256 GB) with resumable uploads
- Process uploads into multiple resolutions and formats and generate thumbnails
- Viewers watch with adaptive quality that adjusts to their network
- Video page: title, description, channel, likes, view count, comments
- Search and a home feed of recommendations (high level only)
- Creators see processing status and basic analytics (views, watch time)
Non-functional
- Scale: ~500 hours of video uploaded per minute; ~1B hours watched per day
- Playback start time < 2 s p90; rebuffering ratio < 0.5% of watch time
- Uploads never lost once acknowledged; processed video durable (11 nines)
- Standard-definition renditions available within minutes of upload; HD shortly after
- Video page metadata API < 100 ms p99; 99.99% availability for playback
- Work on 2G/3G-class networks in Tier-2/3 India (144p/240p, small segments)
Out of scope (say it out loud)
- Recommendation model internals (treat as a service that returns video ids)
- Ads insertion and monetisation
- Live streaming (separate design)
- Copyright matching (Content ID) internals
2 Estimates
3 API
| Endpoint | What it does |
|---|---|
POST/v1/uploads | Start a resumable upload session; returns upload_id and upload URL |
PUT/v1/uploads/{upload_id} | Upload a chunk with Content-Range; the client resumes from the last acknowledged byte after a drop |
POST/v1/videos | Create the video record: title, description, visibility, upload_id |
GET/v1/videos/{id} | Video page metadata: title, channel, counts, available renditions |
GET/v1/videos/{id}/playback | Returns signed manifest URLs (DASH/HLS) and the CDN host chosen for this client |
GEThttps://cdn…/{id}/{rendition}/seg_{n}.m4s | Media segment fetched directly from the CDN |
POST/v1/events/watch | Batched playback events (start, progress every N seconds, quality switches, rebuffer) |
GET/v1/videos/{id}/status | Processing status for the creator |
4 Data model
videosMySQL sharded with Vitessvideo_id (PK, random 11-char id)channel_idtitledescriptiondurationstatus (uploading/processing/ready/blocked)visibilityrenditions (list)thumbnail keyscreated_atSharded by video_id; a secondary lookup table (channel_id → video_ids) serves channel pages. Hot rows cached in Memcached/Redis.
channelsMySQL (Vitess)channel_id (PK)owner_user_idnamesubscriber_count (approximate)settingsSmall and relational.
raw uploadsObject storage (GCS/S3)key = upload_idoriginal filechecksumKept for re-encoding with new codecs later; moved to colder storage classes over time.
segmentsObject storage + CDNkey = video_id/codec_resolution/seg_n.m4splus manifest.mpd / master.m3u8Immutable files, so they cache perfectly. Popular videos live in edge caches; the long tail is fetched from origin on demand.
view_countsBigtable/Cassandra counters + Redisvideo_idtotal_viewslikes; per-hour buckets for analyticsUpdated by stream aggregation in batches, not per view.
watch_eventsKafka → data warehouse (BigQuery/ClickHouse)user_idvideo_idsession_idpositionevent_typebitratetsFeeds view counting, creator analytics, recommendations and QoE dashboards.
commentsBigtable / Cassandravideo_id (partition)comment_id (time-ordered)user_idtextparent_idlike_countPartitioned by video; very popular videos need paging and ranking (top comments) precomputed.
5 Architecture
Hover a box to highlight its connections.
6 Request flows
Upload and process a video
- 1The creator app calls POST /uploads and gets an upload session; it uploads in 8-16 MB chunks with Content-Range so a dropped mobile connection resumes instead of restarting.
- 2The upload service writes chunks to object storage, verifies the final checksum, creates the video row with status=processing and publishes UploadCompleted to Kafka.
- 3The transcode orchestrator builds a DAG: probe the file, split it into ~10-second chunks at keyframe (GOP) boundaries, encode each chunk for each rendition in parallel, then merge and package.
- 4Low resolutions (144p-480p H.264) get the highest priority so the video can go live within minutes; 1080p/4K and VP9 follow; AV1 is produced later only if the video becomes popular.
- 5In parallel, thumbnails are extracted, audio is normalised, captions are auto-generated, and moderation and copyright matching run.
- 6The packager writes CMAF segments plus DASH and HLS manifests to segment storage.
- 7When the minimum ladder and moderation pass, the metadata service flips status to ready (or blocked) and notifies the creator and subscribers.
Watch a video
- 1The app fetches /videos/{id} (metadata from cache) and /videos/{id}/playback, which returns a signed manifest URL on a CDN hostname chosen for the user's ISP and location.
- 2The player downloads the manifest listing renditions (e.g. 144p at 100 kbps up to 1080p at 5 Mbps).
- 3It starts with a low-to-medium bitrate to start fast, fetching ~2-4 s segments from the nearest edge (often a cache inside the user's ISP).
- 4The ABR algorithm watches throughput and buffer level, switching up when the buffer is healthy and down before it empties.
- 5On a cache miss, the edge fetches from a regional mid-tier cache (origin shield), and only then from origin storage.
- 6The player batches watch events (started, progress every 30 s, rebuffer) and sends them to the events collector.
Count a view
- 1Watch events land in Kafka partitioned by video_id.
- 2A Flink job filters invalid views (bots, repeated reloads, too-short watches) using per-user/per-IP state.
- 3It aggregates valid views per video in 10-30 s windows and writes increments to the counters store.
- 4The video page reads the total from a cache; counts may lag a few seconds to minutes, which is acceptable.
7 Deep dives
The transcoding pipeline as a parallel DAG
Encoding a 2-hour 4K video serially into ten renditions would take many hours. Instead, the orchestrator splits the source into independent chunks at keyframe (GOP) boundaries, typically a few seconds to tens of seconds each, and encodes every (chunk, rendition) pair as a separate task across thousands of workers. A merge step concatenates the encoded chunks and a packager produces CMAF segments with DASH and HLS manifests. Model it as a DAG in a workflow engine (Temporal or an internal scheduler) so each task is retried independently, progress is checkpointed, and a worker crash costs one chunk, not the whole video. Prioritise: produce 360p first so the video is watchable within minutes, then higher resolutions. Spend compute where it pays off: every upload gets H.264 for compatibility and VP9 for mid-popularity, but AV1 encoding is expensive and is done only after a video crosses a view threshold, because the bandwidth saving (~30% vs VP9) only matters when many people watch. Workers should be spot/preemptible instances, since tasks are idempotent and short. Keep the original upload so you can re-encode the catalogue when a better codec arrives.
Adaptive bitrate streaming and CDN tiering
Video is cut into short segments (2-6 s) available at several bitrates. The player picks the next segment's bitrate from measured throughput and buffer health (buffer-based algorithms like BOLA work well on noisy mobile networks). Short segments react faster but add request overhead; 2-4 s is a common balance. Because segments are immutable files with stable URLs, they cache perfectly. Delivery is tiered: edge caches inside ISPs (Google Global Cache, Netflix Open Connect style), regional PoPs, a mid-tier origin shield, and finally origin storage. Head content (the top few percent of videos, which draw most views) is almost always served from the edge; the long tail is fetched on demand and may come from a regional tier with slightly higher start time. The playback service steers each client to a good CDN node by IP, ISP and node load, and signs URLs with a short expiry so links cannot be hot-linked forever. For India, publishing low rungs (144p at ~80-100 kbps, 240p) and starting at a conservative bitrate cuts startup failures on congested networks.
Metadata at scale: sharded MySQL and caching
Video metadata is small (a few KB per video) but read very often. YouTube scaled MySQL by building Vitess, which shards tables transparently, routes queries by a keyspace id, and handles resharding and connection pooling. Shard videos by video_id so reads are spread evenly; channel pages use a secondary table keyed by channel_id. Put a cache (Memcached/Redis) in front: the read/write ratio is extreme (a video is written a few times and read millions of times), so a 95%+ hit rate is normal. Do not store fast-changing counters (views, likes) in the same row: they would cause write hot spots and cache invalidation storms. Keep them in a separate counters store and merge them in the API layer. Video ids are random (not sequential) so new uploads do not all land on one shard and ids cannot be enumerated.
View counting without a write per view
Incrementing a database counter on each view is ~60k writes/s on average with extreme hot keys: a viral music video can get 50k views/s on one row. Instead, the player sends watch events to a collector, events go to Kafka partitioned by video_id, and a stream processor (Flink) validates and aggregates them. Validation matters because view counts drive money and ranking: a view counts only after a minimum watch time, repeated reloads by the same user or IP within a window are dropped, and known bot patterns are filtered. The aggregator flushes per-video sums every 10-30 seconds, turning millions of events into thousands of writes. For a super-hot video, pre-aggregate inside each partition and shard the counter (several sub-counters summed on read). The public count can be eventually consistent; YouTube itself has historically frozen or delayed counts while validating suspicious spikes. Exact numbers for creator payouts are computed later in batch from the warehouse.
8 Trade-offs
Encode everything up front vs on demand
Encoding every rendition and codec for every upload wastes compute: most videos get few views. Encode a baseline ladder for all and add expensive codecs (AV1, 4K HDR) only when popularity justifies it. The trade is slightly worse quality-per-bit for long-tail videos in exchange for large compute savings.
Segment length
2 s segments adapt quickly and start faster but mean more requests and worse compression (more keyframes). 6-10 s segments are efficient but adapt slowly on mobile. 2-4 s is a good default for VOD.
Own CDN vs commercial CDN
At ~100 Tbps, placing your own caches inside ISPs is far cheaper and faster than paying per GB, and ISPs welcome it because it cuts their transit. A smaller platform should start with commercial CDNs and multi-CDN steering.
Exact vs approximate public counts
Exact real-time counts need transactional increments on hot rows. Approximate, slightly delayed counts from stream aggregation scale easily and allow fraud filtering first. Creator payouts use exact batch numbers.
9 Bottlenecks
Viral video or premiere spike
A sudden spike causes many simultaneous edge misses for the same segment. Request coalescing at the edge and the origin shield (one upstream fetch, many waiters) plus pre-warming edges for scheduled premieres keep origin load flat.
Transcoding backlog
Upload peaks (evenings, festivals) can outgrow the encoding fleet. Autoscale on queue depth with spot instances, prioritise low renditions and partners, and let high renditions catch up later.
Storage growth
Petabytes per day accumulate forever. Move old originals and rarely watched renditions to colder storage classes, delete renditions that can be regenerated, and use erasure coding instead of 3x replication.
10 Failure handling
Transcode worker dies mid-task
The workflow engine notices the missed heartbeat and reschedules that chunk task on another worker. Outputs are written to deterministic keys, so a retried task simply overwrites; the video is delayed by seconds, not reprocessed.
CDN node or PoP fails
The playback service and DNS steer clients to the next-best node; players retry a failed segment against an alternate host listed in the manifest. Viewers may see one quality drop, not an error.
Metadata database shard down
Serve video pages from cache (slightly stale) while Vitess fails over to a replica. Playback of already-started videos is unaffected because segments come from the CDN.
Upload interrupted
Resumable uploads keep acknowledged byte ranges; the client queries the session and continues from the last offset. Incomplete sessions expire after a few days.
11 What impresses
- Does the bandwidth estimate (~100 Tbps) and concludes the CDN is the system
- Explains chunked parallel transcoding as a DAG with per-task retries
- Encodes expensive codecs only for popular videos and explains why
- Separates hot counters from video metadata and aggregates views in a stream
- Mentions request coalescing and origin shield for viral spikes
- Designs for low-bandwidth Indian networks with low ladder rungs and conservative start
12 Mistakes
- Serving video bytes from application servers
- Transcoding synchronously in the upload request
- Single-file progressive download with no adaptive bitrate
- Incrementing a database row for every view
- Ignoring storage and compute cost of encoding every format for every upload
- Forgetting resumable uploads for multi-GB files on mobile networks
13 Follow-ups
Lessons this design uses
Practice questions
- Design the API for uploading large files, like a 2 GB video, from a mobile app. What does the client call and in what order?
- An API starts a video transcode that takes 5-10 minutes. How do you design the API so clients get the result?
- Design the processing pipeline that turns an uploaded 1 GB, 20-minute video into something users can stream smoothly on both 4G phones and smart TVs.
Saved on this device. Create a free account to keep it on every device.
Practise this with Sam
A real mock interview, out loud, with an honest scorecard. Free to start.