Skip to main content

Design YouTube or Netflix

A video streaming platform supporting fast video upload and smooth, adaptive streaming.

synchronous: caller waits
asynchronous: fire & forget

Denser dots = higher throughput. Hover any edge for its full contract.

//The Contract

Requirements

Functionalwhat the system must do
  • Creators can upload multi-gigabyte videos, and interrupted uploads resume from the failed chunk instead of restarting
  • Viewers can stream any published video with near-instant startup
  • Playback quality adapts automatically to the viewer's available bandwidth (ABR)
  • Viewers can browse video metadata — titles, thumbnails, duration, processing status
  • Uploaded videos become streamable automatically after asynchronous processing
Non-functionalhow well it must do it
  • High availability — the streaming read path must survive failures in the upload and processing path
  • Low latency — sub-second video startup for popular content served from edge caches
  • Massive scale — millions of concurrent streams, hundreds of hours of video ingested per minute
  • Durability — an original upload is never lost once the multipart upload completes
  • Cost efficiency — bandwidth and storage dominate cost, so origin egress must be minimized
//Back of the Envelope

Scale Estimates

Rough, order-of-magnitude numbers. The point is to justify the architecture, not to be exact.

Daily active users
100M
each watching ~5 videos per day
Video ingested
500 hrs/min
YouTube-scale upload rate
New storage / day
~2 PB
originals plus every transcoded variant
Read : write ratio
200 : 1
views dwarf uploads — optimize the read path
Peak concurrent streams
10M+
virtually all served by the CDN, not origin
Metadata QPS (peak)
~50K
mostly absorbed by the Redis cache
//Why It Looks Like This

System Evolution

No system is born with queues and caches. Every box was added because something was about to break. Play a stage and the diagram above shrinks to what existed at that point in the story.

01

The MVP — one API, one database, one bucket

Every platform starts embarrassingly small. A stateless API issues pre-signed URLs so even v1 never proxies video bytes — creators upload straight into one bucket, metadata lands in one database, and viewers simply download the original file to watch it.

This survives a few thousand users. But every viewer pulls the full-size original: a phone on 3G downloads the same gigabytes as a fiber desktop, startup takes forever, and most of the transfer is wasted.

02

Make it watchable — the transcoding pipeline

Scale pressure: Raw originals are unwatchable at scale — a phone on hotel Wi-Fi cannot stream a 4K master file

Stop serving what creators upload; start serving what players need. When an upload completes, the bucket emits an object-created event into a queue; a handler wakes the orchestrator, which fans one video out into hundreds of parallel encode jobs — every resolution × bitrate, split into few-second segments written to a second bucket.

The queue is the load-bearing decision here: uploads finish instantly even when every encoder is busy, failed jobs retry from the queue, and queue depth becomes the honest autoscaling signal for the worker fleet.

03

Go global — the CDN and every screen

Scale pressure: Viewers far from the origin region wait seconds for startup, and origin egress is billed per gigabyte

Segments are static files, and static files belong at the edge. A CDN now fronts transcoded storage: popular segments are cached close to viewers, and a cache miss pulls from origin once, then serves everyone nearby from the edge.

With sub-second startup available everywhere, the audience multiplies — mobile apps and smart TVs join the web client, all speaking the same manifest-driven ABR protocol. Origin ends up serving only the long tail.

04

Survive popularity — cache the read path

Scale pressure: Views outnumber uploads 200 : 1, and viral traffic concentrates on a handful of videoIds — hot Cassandra partitions saturate

Video bytes scale beautifully now, but every play still begins with a metadata read, and viral traffic hammers the same few rows. A Redis cache in front of Cassandra absorbs nearly all reads for hot videos: miss → read Cassandra → back-fill for the next viewer.

This is the finished architecture: the write path (upload → transcode) and the read path (CDN → player) are fully decoupled, and every tier scales on its own signal.

//Follow the Data

Request Flows

A diagram shows what exists; a trace shows what happens. Press play on a flow, or click any step, and the diagram above lights up the exact path that request takes.

Flow 01

Upload & process a video

From the creator pressing upload to the video being streamable. Notice that the raw video bytes never touch an application server.

Flow 02

Stream a video (ABR)

What happens between pressing play and smooth, adaptive playback.

//Component Breakdown

Key Components

Every box on the canvas, and the job it does. Click a card to locate it in the diagram; click the node itself for the full deep dive.

client×3
network×2
compute×4
database×1
cache×1
queue×1
storage×2
//Deep Dive

Architecture Breakdown

Architecture Overview

This architecture is designed for a large-scale video streaming platform similar to YouTube or Netflix. The system separates the control plane (metadata, APIs, upload management, orchestration) from the data plane (video storage, transcoding, CDN delivery). This separation allows lightweight API services to scale independently from the bandwidth-intensive video delivery pipeline. Application servers never proxy video files. Instead, clients upload directly to object storage and stream directly from the CDN, allowing the platform to support millions of users without overwhelming backend servers.

The architecture consists of two major workflows:

  • Upload Pipeline converts a raw uploaded video into multiple optimized streaming formats.
  • Streaming Pipeline delivers those processed videos efficiently using adaptive bitrate streaming.

The entire system is built around asynchronous processing, distributed storage, stateless services, and aggressive caching to maximize scalability while minimizing infrastructure costs.

Upload Architecture

When a creator uploads a video, the application server does not receive the video itself. Instead, the client first requests a pre-signed upload URL from the API service.

The API authenticates the user, creates a multipart upload session in blob storage, stores the initial metadata (title, description, uploader, visibility, etc.), and returns a temporary upload URL. This URL grants permission to upload directly into blob storage without exposing permanent credentials.

The client splits the video into multiple chunks and uploads them directly to blob storage using multipart upload. Because every part is uploaded independently, interrupted uploads can resume from the failed chunk instead of restarting the entire transfer. This significantly improves reliability for multi-gigabyte uploads and removes the application servers from the critical data path.

After all parts have been uploaded, the client completes the multipart upload request. Blob storage assembles the individual parts into the final raw video object.

The creation of the new object automatically generates an object-created event. Rather than immediately processing the video, this event is published to a queue. Using a queue completely decouples uploads from processing, allowing uploads to finish instantly even if the transcoding cluster is busy.

Asynchronous Processing Pipeline

A Transcoding Orchestrator continuously consumes upload events from the queue.

Instead of treating transcoding as a single long-running task, the orchestrator constructs a Directed Acyclic Graph (DAG) representing every processing step and the dependencies between them. This allows independent tasks to execute simultaneously while preserving the required execution order.

A typical DAG contains operations such as:

  • Splitting the original video into GOP-aligned segments
  • Encoding each segment into multiple resolutions (240p, 360p, 480p, 720p, 1080p, 4K)
  • Encoding multiple bitrates for each resolution
  • Generating thumbnails
  • Creating preview images
  • Extracting audio if required
  • Applying watermarking
  • Creating streaming manifests
  • Updating processing status

Once the video has been split into independent segments, hundreds of encoding jobs can execute in parallel across many worker machines. Since transcoding is extremely CPU-intensive, parallel execution dramatically reduces total processing time.

Workers never exchange large video files directly. Instead, intermediate outputs are written back to blob storage, and workers simply pass object references between DAG stages. This minimizes network traffic and allows workers to remain completely stateless.

When all DAG tasks complete successfully, the processed outputs include:

  • Video segments
  • Adaptive bitrate variants
  • HLS or MPEG-DASH manifest files
  • Thumbnail images
  • Updated metadata

The orchestrator marks the video as available for streaming.

Adaptive Bitrate Video Generation

Raw uploaded videos are not streamed directly.

During transcoding, each video is converted into multiple combinations of:

  • Resolution
  • Bitrate
  • Codec
  • Container format

Each version is then divided into short video segments, typically lasting only a few seconds.

The transcoder generates one or more manifest files (such as HLS or MPEG-DASH manifests). Rather than containing video data, these manifests describe:

  • Available quality levels
  • Segment ordering
  • Segment URLs
  • Codec information
  • Bitrate information

The manifest acts as an index for every streamable version of the video and enables adaptive bitrate streaming.

Metadata Layer

Video files themselves are far too large to store inside a traditional database.

Instead, the metadata service stores only structured information such as:

  • Video ID
  • Title
  • Description
  • Upload timestamp
  • Duration
  • Processing status
  • Thumbnail URLs
  • Manifest URL
  • Owner information

A horizontally scalable database such as Cassandra is used because metadata reads and writes occur at massive scale while requiring high availability and partition tolerance. Records are partitioned using the Video ID, allowing requests to be distributed evenly across database nodes.

Frequently accessed metadata is cached inside Redis.

Most video requests first check Redis. If metadata is already cached, the database is bypassed entirely. Otherwise, the metadata is loaded from Cassandra and inserted into Redis for future requests.

This cache dramatically reduces database load for popular videos.

Streaming Architecture

When a viewer opens a video, the client first requests video metadata from the API service.

The metadata contains information such as the title, description, thumbnail, duration, and most importantly, the URL of the generated manifest file.

The client downloads the manifest before requesting any video content.

The manifest informs the player about every available quality level and provides the location of every segment belonging to each quality.

The player estimates the user's available bandwidth and selects an initial quality.

Instead of downloading the complete video, the player requests only the first segment from the CDN.

While the first segment is being played, subsequent segments are downloaded in the background.

After each segment finishes downloading, the player measures:

  • Current throughput
  • Buffer size
  • Download latency
  • Playback performance

If bandwidth improves, the next segment can be requested at a higher quality.

If bandwidth decreases, the next segment is requested using a lower bitrate.

Because switching occurs only between segment boundaries, playback continues smoothly without restarting the video.

This mechanism is known as Adaptive Bitrate Streaming (ABR) and is the standard approach used by modern streaming platforms.

CDN Distribution

Serving every video request directly from blob storage would generate enormous bandwidth costs and introduce high latency for users located far from the storage region.

Instead, transcoded segments are distributed through a Content Delivery Network.

CDN edge servers cache video segments close to users around the world.

When a segment is requested:

  • If the segment already exists at the edge, it is returned immediately.
  • Otherwise, the CDN retrieves it from origin storage, caches it, and serves it to the client.

Since each segment is only a few seconds long, only the requested portions of the video are transferred instead of the entire file.

The CDN therefore handles the overwhelming majority of read traffic, while origin storage primarily acts as the durable source of truth.

Hybrid CDN Strategy

Caching every uploaded video inside the CDN would be prohibitively expensive because the majority of uploaded content receives very few views.

Instead, the architecture follows a hybrid caching strategy.

Highly popular videos remain cached in CDN edge locations to provide extremely low latency and reduce origin traffic.

Less frequently viewed videos are streamed directly from blob storage whenever necessary.

As popularity changes over time, videos naturally migrate between origin storage and CDN caches according to demand.

This balances infrastructure cost with user experience.

Scalability Characteristics

The architecture is designed so that every major component can scale independently.

The API layer remains completely stateless, allowing additional instances to be added behind a load balancer whenever request volume increases.

Blob storage provides virtually unlimited storage capacity for raw uploads and transcoded outputs.

The queue absorbs upload spikes by buffering processing requests.

The DAG-based transcoding system scales horizontally by simply adding more worker nodes.

Metadata storage scales through partitioning across database nodes.

Redis reduces repeated database queries for popular content.

The CDN absorbs nearly all streaming traffic, preventing backend services from becoming bandwidth bottlenecks.

Since upload, processing, metadata management, and streaming are loosely coupled through asynchronous communication and object storage, failures in one subsystem rarely impact the others. The resulting architecture achieves high availability, efficient resource utilization, and the ability to support millions of concurrent uploads and streams while maintaining low latency and predictable operational costs.

//Trade-offs

Design Decisions

An architecture is a record of trade-offs. For every major choice here: what won, what lost, and why the constraints made it so.

01

Clients talk to storage directly

ChosePre-signed URLs + multipart upload
OverProxy uploads through the API servers

Video ingress is measured in petabytes. If those bytes flowed through the API tier, it would have to scale with video traffic instead of request traffic — thousands of servers doing nothing but relaying chunks. Pre-signed URLs let blob storage do what it is built for while the API tier stays small, stateless and cheap. Multipart upload adds resumability for free: every chunk retries independently.

02

Decouple upload from processing

ChoseObject-created events into a queue
OverSynchronous transcode on uploadPolling storage for new objects

Transcoding a 4K video can take longer than uploading it. Coupling the two would make upload latency depend on encoder capacity — and an encoder outage would break uploads entirely. The queue absorbs spikes, gives failed jobs a retry path, and lets the transcoding fleet autoscale on a single honest signal: queue depth.

03

Transcoding as a DAG

ChoseSplit → parallel per-segment encodes → assemble
OverOne monolithic FFmpeg job per video

A single job encodes a two-hour movie in hours; hundreds of parallel segment jobs do it in minutes. GOP-aligned splitting makes each segment independently encodable, workers stay stateless by passing object references instead of video bytes, and a failed task retries alone rather than restarting the entire encode.

04

Cassandra for metadata

ChoseWide-column store partitioned by videoId
OverSharded PostgreSQLDynamoDB

Metadata is written at ingest scale and read at viewing scale, but needs no cross-video joins or transactions — a naturally key-partitioned workload. Cassandra gives linear horizontal scale and stays available under partition (AP). A relational database would force manual sharding for little benefit; DynamoDB is a fine managed take on the same idea.

05

Hybrid CDN strategy

ChoseEdge-cache popular content, serve the long tail from origin
OverCache everything at the edgeServe everything from origin

Views follow a power law: a tiny fraction of videos produce nearly all traffic. Caching everything pays premium edge storage for content nobody watches; serving everything from origin pays egress and latency on every view. The hybrid puts 90%+ of traffic on the edge while cold content lives quietly in cheap object storage.

//What Breaks First

Bottlenecks & Failure Modes

Reading a system means sensing where it cracks under 10× load. These are the pressure points of this design, and how it holds.

Risk 01

Viral video thundering herd

Failure mode

A video going viral sends millions of players after the same segments and the same metadata within minutes. Uncached, the stampede hits Cassandra and origin storage simultaneously.

Mitigation

Layered absorption: the CDN soaks segment traffic, Redis soaks metadata reads, and request coalescing collapses concurrent identical cache misses into a single origin fetch.

Risk 02

Transcoding backlog during upload spikes

Failure mode

A global event can push encode demand far past worker capacity. Queue depth grows and time-to-publish stretches from minutes to hours.

Mitigation

Workers autoscale on queue depth, and priority lanes publish a fast 360p/720p rendition first — the video is watchable in minutes while 4K renders later.

Risk 03

Hot partition on the metadata store

Failure mode

Partitioning by videoId spreads load evenly — until one videoId is 1000× hotter than the rest. That single Cassandra partition becomes the bottleneck no matter how many nodes the cluster has.

Mitigation

The Redis cache absorbs nearly all reads for hot keys, counters batch their writes, and truly extreme keys can be salted across sub-partitions.

Risk 04

Origin egress cost blow-up

Failure mode

Every CDN miss is an origin read billed by the gigabyte. A degraded cache hit ratio silently turns bandwidth into the biggest line item in the budget.

Mitigation

Few-second segments mean only watched portions ever transfer, tiered caching (edge → regional shield) keeps misses regional, and popularity-based prefetch warms edges ahead of predictable spikes.

//Break Things on Purpose

Failure Lab

Most of this architecture exists because any one box can die. Take a component offline and the diagram above shows the blast radius: what goes down, what degrades, and what the user feels.

API Service (Stateless)

REST API

The control plane is gone: no browsing, no new uploads, no pressing play on new videos. Anyone already watching keeps watching — the CDN path never calls the API.

Metadata Database

Cassandra

Browsing, search and pressing play fail for anything not already cached — and new uploads cannot register. Streams already playing continue untouched: the player has its manifest.

Metadata Cache

Redis

Nothing visibly breaks for a minute — then every metadata read lands raw on Cassandra and page loads crawl for exactly the videos everyone is watching.

Content Delivery Network (CDN)

CDN

Playback does not stop, but startup jumps from milliseconds to seconds and quality drops — every viewer is suddenly streaming from one distant origin.

Task Workers (DAG)

Container

Time-to-publish stretches from minutes toward hours — uploads keep landing, but nothing becomes streamable until encode capacity returns.

Upload Completion Queue

SQS

Creators notice nothing — uploads still complete. But new videos silently stay 'processing' forever: the pipeline's trigger is gone.

//Active Recall

Test Yourself

If you can answer these without scrolling back up, the architecture is yours. Try each one out loud before revealing.

//Go Deeper

Further Reading

Patterns used in this design
//A Word

From the Creator

Every great system starts as a sketch on a whiteboard. The ability to zoom out and see the whole picture (how services connect, where data flows, what breaks and why) is what separates engineers who build features from engineers who build systems. This diagram is more than boxes and arrows. It's a map of decisions, trade-offs, and intentional design.

Studying architectures isn't just about passing interviews. It's about training your intuition. The more systems you take apart, the better you get at sensing where a monolith will crack, where a queue belongs, or when a cache is hiding a deeper problem. You start seeing patterns instead of chaos.

So keep reading, keep tracing those edges, keep asking "why this way and not that way." The engineers who truly understand large systems are the ones who never stop being curious about how things fit together. That curiosity is the only ingredient that really matters.

Atharva Arbat@arbat_atharva

//Explore

More Patterns