System design template

Video streaming architecture.

Around ninety-nine percent of the bytes never touch your servers, which means most of this design is about preparing files so the CDN can do the work.

Download for macOS
v0.1.33 · .dmg · Apple Silicon & Intel
Signed & notarized by Apple · opens without a Gatekeeper warning
sha256 698955a0187bc039f4c74f5d05a9f10fbb27376a45788a0a241d1326b73873c7
Download for Windows instead
$curl -fsSL https://lucidtrain.com/install.sh | sh
Video streaming service architecture. 11 components across 4 tiers.
Video streaming service architecture. Rendered by the same ELK layout engine the app runs: the agent emits components, tiers and edges, and the engine places them, so the boxes cannot overlap.

The components

Every row below is read from the graph that produced the diagram above, so the two cannot disagree.

ComponentTierWhy it is there
PlayerClientAdaptive bitrate, picks a rendition
CDNEdgeServes ~99% of bytes
API gatewayEdgeSupporting component
Upload serviceApplicationSupporting component
Transcode farmApplicationOne job per rendition, fan-out
CatalogApplicationSupporting component
DRM & licensingApplicationSupporting component
Job queueDataSupporting component
Raw storeDataMezzanine masters
Packaged storeDataHLS and DASH segments
PostgresDataSupporting component

Design decisions worth arguing about

A diagram shows what was chosen. It does not show what it cost, and that is usually the part that matters in a review or an interview.

Transcode once, serve many times

Transcoding on demand sounds efficient and is ruinous: it is expensive, slow, and repeated for every viewer. Producing every rendition on upload trades storage, which is cheap, for compute, which is not. The cost is upload-to-available latency measured in minutes rather than seconds, and a large multiplier on storage since every title exists at several bitrates.

One job per rendition, so failure is granular

Treating a whole video as one transcode job means a failure at ninety percent redoes everything, and one very long video occupies a worker for hours. Fanning out per rendition, and per segment for long content, makes each unit small, retryable and parallel. It costs an orchestration layer that knows when all the pieces of a title are done, which is more coordination than a single job needs.

Adaptive bitrate moves the decision to the client

The player measures its own throughput and picks a rendition, which handles varying networks far better than any server-side guess. The consequence is that you must produce and store a ladder of renditions whether or not anyone watches the lower ones, and that quality complaints become hard to diagnose because the server did not choose what was delivered.

DRM constrains everything downstream

Licensed content requires encrypted segments and a license server, which means the CDN can no longer serve fully anonymously, playback needs platform-specific DRM systems, and testing requires real devices. If the catalog does not need it, not having DRM removes a large amount of complexity. Once one title needs it, the whole delivery path is shaped by it.

How it changes with scale

Delivery scales with the CDN, which is someone else's problem and your largest bill. Transcoding scales with catalog growth rather than viewership and is bursty, which makes it a good fit for preemptible capacity. Storage grows monotonically and never shrinks, so lifecycle policies moving cold titles to cheaper tiers matter more over time than any compute optimisation.

Where it breaks first

A thundering herd on a new release. Everyone requests the same first segments within minutes, and until the CDN has them cached those requests all reach the origin. Pre-warming the edge before a scheduled release is the standard answer, and forgetting to do it is the standard incident.

Draw this yourself

Open the Diagram tab and describe the system. The agent emits a semantic graph rather than coordinates, so you can edit the components and the layout re-solves instead of drifting.

shell
$ Diagram a video streaming service: upload service writing mezzanine masters to object storage, a job queue feeding a transcode farm producing HLS and DASH renditions, a catalog service, DRM licensing, and CDN delivery to an adaptive bitrate player.

When the shape is right, Implement in code turns the canvas into a markdown specification, every component, every relationship and the notes, and starts a real turn in the Code tab with it.

FAQ

Questions about this design

HLS or DASH?

Both, usually. HLS is required on Apple platforms and DASH is more common elsewhere. They can share the same encrypted segments with different manifests, which keeps the storage multiplier from doubling.

How many renditions should the ladder have?

Enough to cover the range of networks your audience actually has, typically five to seven. Every extra rung costs transcode time and storage for every title, so the tail rungs should be justified by real playback data.

Should uploads go through the API?

No. Presigned uploads direct to object storage keep large files off your servers entirely. The API issues the credential and records metadata, and never sees the bytes.

Where does live streaming differ?

Almost everywhere. There is no upload-then-transcode phase, latency is a hard requirement rather than a preference, and there is no opportunity to retry a failed segment. It is a different architecture that happens to share a delivery layer.

More templates