Vibe Engines
YouTube
System Design

Design a Live Streaming System

Step 1 / 9

Learn system design by building a live video streaming system like Twitch or YouTube Live step by step.

The numbers to beat1 inseveral renditions outABRplayer picks best rungper broadcastertranscode cost

The whole design, in writing

Learn system design by building a live video streaming system like Twitch or YouTube Live step by step. An interactive guide covering ingest of a broadcaster stream, transcoding into an adaptive bitrate ladder, segmenting into HLS/DASH chunks, CDN fan-out to millions of viewers, the latency-vs-scale tradeoff, live chat, DVR/VOD, and the unhappy paths (thundering herd, low-latency modes, geo-distribution).

Every step of the build above, written out: the problem each piece solves, the option that was taken and the ones that were not, the numbers, and how it fails in production.

The big idea

What makes live streaming hard?

One broadcaster, millions of viewers, all watching the same moment within seconds of each other — on phones, TVs and laptops, on every kind of network, all over the planet. It's the opposite shape of a video call (few-to-few, ultra-low latency): this is one-to-millions, where scale matters more than shaving off the last second.

BroadcasterRTMP push
New in this step: Broadcaster.

A live streaming system ingests one high-quality stream, transcodes it into a ladder of qualities, segments it into small HTTP chunks, and fans those out through a CDN to millions. The genius move: turn live video into ordinary cacheable files so the whole internet's caching infrastructure does the scaling for you.

What the new pieces do

Broadcasterclient
The streamer's encoder pushing one continuous high-quality video stream up to the platform in real time.

Step 1 · The shape of the problem

One-to-millions, not few-to-few

It's tempting to reach for WebRTC (video-call tech). But a call is a handful of people at ~150ms latency; a stream is one source to millions at a few seconds' latency. Why does that difference flip the whole design?

BroadcasterRTMP push
The system as it stands at this step.

Why can't you just use video-call (WebRTC/SFU) tech for a million-viewer stream?

  1. WebRTC encodes fine; the mismatch is scale and cost. Real-time peer connections to millions of viewers are wildly expensive and unnecessary, since viewers only consume (never send) and can tolerate a few seconds of delay.

  2. It's the opposite — a broadcast tolerates seconds of latency, while a call needs sub-150ms. That tolerance is exactly what lets streaming trade a little delay for massive, cheap scale via HTTP/CDN.

  3. Because viewers don't send media and can accept a few seconds of delay, you don't need per-viewer real-time connections. Instead you turn video into cacheable HTTP segments a CDN fans out to millions — far cheaper and more scalable than an SFU mesh.

A stream is one-to-millions: viewers only consume and can tolerate a few seconds of delay. That tolerance is a gift — it lets you avoid per-viewer real-time connections and instead turn video into cacheable HTTP segments that a CDN fans out to millions cheaply. You trade a few seconds of latency for essentially unlimited, low-cost scale.

Why this piece earns its place

The phrase viewers only consume is doing a lot of work here, and it describes a role, not a person. The day the product adds a guest slot, a call-in or a co-stream, someone in that audience starts sending media, and the instinct is to carve them a shorter delivery path — a special real-time route down to one seat. That is the wrong shape: it rebuilds the expensive per-viewer architecture you just rejected, inside the cheap one, for a single viewer. The clean answer is to move them across the line instead. A participant is a broadcaster: they get an ingest connection, their media is mixed into the source before anything downstream sees it, and the millions still watching stay exactly where they were, pulling segments. Keep the asymmetry — a few pushers, many pullers — and promote people between the two sides rather than blurring the boundary, because the moment a viewer can be served specially, the economics that made this design work stop being true.

Step 2 · Get the stream in

Ingest

First, the broadcaster's single high-quality stream has to reach you reliably and continuously. What receives it, and how?

BroadcasterRTMP pushIngestRTMP / SRT
New in this step: Ingest.

Run an ingest endpoint that accepts the broadcaster's push over a real-time protocol — RTMP (classic), SRT (resilient over lossy links), or WebRTC (lowest latency). It authenticates the stream key, handles reconnects, and forwards the raw stream into the processing pipeline. Ingest is per-broadcaster (there are far fewer broadcasters than viewers), so it's the cheap side of the system.

Why this piece earns its place

Everything downstream is fed by one live connection from one encoder, which makes ingest the only place in this design where a single failure takes the whole broadcast off the air — the CDN has hundreds of edges and the ladder has several renditions, but the broadcaster has one socket. So treat a reconnect as a first-class event rather than an error path. Encoders retry, and many can be pointed at a backup ingest URL, which means the stream key has to resolve to a broadcast session that a different ingest node can adopt, not to whichever box happened to answer first. The subtler half is downstream: a reconnected encoder restarts its own timestamps, and if the pipeline reads that as a brand-new broadcast it starts a fresh output and every player in the world is left waiting on one that stopped advancing. Carry the session across the gap and signal the break as a discontinuity, so a dropped uplink costs viewers a stutter instead of the stream.

What the new pieces do

Ingestgateway
Receives the broadcaster's stream (RTMP/SRT/WebRTC), authenticates it, and hands it to the processing pipeline.

Step 3 · One stream, every device

Transcoding into a bitrate ladder

The broadcaster sends one quality (say 1080p at 6 Mbps). But viewers are on 4K TVs and on phones with 1 Mbps. Send everyone 1080p and the phone buffers forever; send everyone low-res and the TV looks awful. How do you serve all of them?

IngestRTMP / SRTTranscoderbitrate ladder
New in this step: Transcoder.

One incoming quality, viewers with wildly different devices/bandwidth. How do you serve all?

  1. The transcoder re-encodes the incoming stream into several resolution/bitrate versions. The player then does adaptive bitrate — measuring its bandwidth and switching to the rendition that plays smoothly. One upload becomes many qualities, one per network condition.

  2. Broadcasters have limited upload bandwidth (like the mesh problem) and can't send many renditions at once. The platform transcodes centrally so the broadcaster uploads just one stream.

  3. A phone on 1 Mbps can't "cope" with a 6 Mbps stream — it buffers endlessly. You must offer lower renditions so each viewer streams a bitrate their network can sustain.

Transcode the source into an adaptive bitrate ladder — several renditions at different resolutions/bitrates (e.g. 1080p/720p/480p/360p, plus audio-only). The viewer's player does ABR: it measures its bandwidth and switches to the highest rendition that plays without buffering, up or down as conditions change. One broadcaster upload becomes a menu of qualities, so every device and network gets a smooth stream.

Why this piece earns its place

The shape of the ladder is the knob, and it is the one cost here that never amortizes. An edge serves the same cached segment to everyone behind it, but transcoding is paid per broadcaster per rung whether a thousand people watch that rung or nobody does. Extra rungs also split the audience: each rendition is its own set of segment URLs, so an edge fills every rung separately, and a rung with two viewers on it misses almost every time it is asked for. Cut too far the other way and the gaps get wide — a player whose bandwidth falls just under 720p has nowhere to land but 480p, so it surrenders quality it could have sustained, and if that drop overshoots it oscillates instead of settling. I would size the ladder from what the audience actually plays rather than from a tidy set of resolutions: pass the source through untouched so the top rung costs nothing to produce, keep a bottom rung cheap enough for a phone on 1 Mbps, and spend encoder time in between only where the viewer histogram is dense.

  • 1 inseveral renditions out
  • ABRplayer picks best rung
  • per broadcastertranscode cost

What the new pieces do

Transcoderservice
Re-encodes the source into multiple resolutions/bitrates (1080p/720p/480p/360p) so any device and network can play.

Step 4 · Make it cacheable

Segment into HTTP chunks

Now the crucial trick. A continuous live stream can't be cached by a CDN — but the CDN is exactly what you need to reach millions. How do you make live video look like something a CDN can serve?

PackagerHLS / DASH chunksOriginsegments + manifest
New in this step: Packager, Origin.

A CDN caches files, but live video is a continuous stream. How do you bridge that?

  1. CDNs aren't built to fan out millions of live persistent streams, and that reintroduces per-viewer cost. The trick is to chop the stream into small files the CDN can cache and serve like any static asset.

  2. Millions connecting to one origin is the exact overload a CDN exists to prevent. You must make the content cacheable so the CDN absorbs the crowd.

  3. The packager splits each rendition into small numbered segments and writes a manifest (playlist) listing them. Viewers fetch segments over plain HTTP and play them back-to-back; new segments append to the manifest as the stream continues. Live video becomes a rolling series of cacheable files — perfect for a CDN.

Segment each rendition into short chunks (2–6s) and write a manifest (playlist) that lists them — this is HLS or DASH. The player fetches the manifest, then downloads segments over plain HTTP and plays them back-to-back; as the stream continues, new segments are appended and old ones age out. Live video is now a rolling set of ordinary cacheable HTTP files — exactly what a CDN was built to serve.

Why this piece earns its place

Segmenting produces two kinds of object with opposite caching behaviour, and the manifest is the one that bites. A segment is immutable the instant it is written: number it, give it a long TTL, and an edge can hold it indefinitely. The manifest is rewritten every time a segment is published, and every player re-fetches it on roughly that same cycle purely to learn the next filename. So the small text file, not the video, becomes the most requested object in the system, and its cache lifetime is a trap in both directions — hold it longer than a segment and players sit at a live edge that has stopped advancing, hold it for nothing and every poll from every viewer lands on origin. The way through is to keep it cacheable but brief so the CDN can coalesce the identical requests arriving inside that window, and, where the protocol allows, let the player hold the request open until the next segment exists, so one waiting connection replaces a loop of hopeful polls.

  • 2–6ssegment length
  • manifestplaylist of segments
  • HTTPcacheable by any CDN

What the new pieces do

Packagerservice
Splits each rendition into small segments (2–6s) and writes a manifest, turning live video into cacheable HTTP files.
Origindata
Holds the latest segments and manifests. The CDN pulls from here; tiered caching shields it from the crowd.

Step 5 · Reach the millions

CDN fan-out

Segments sit on your origin. If a million viewers all pulled them from origin, it would melt. How does one broadcaster's stream reach a million screens without crushing your servers?

CDN Edgefan-outViewersABR playback
New in this step: CDN Edge, Viewers.

Put a CDN in front of the origin. Viewers fetch segments from a nearby edge; the first request for a segment at an edge pulls it from origin (a miss), and the next thousands of viewers on that edge are served the cached copy (hits). One broadcaster's stream is fanned out by hundreds of edges to millions of viewers, while the origin only serves a handful of cache-fills per segment. Tiered/shield caches further protect the origin from the initial fan-in.

Why this piece earns its place

One fill per segment per edge rests on an assumption worth saying out loud: that enough viewers behind the same edge want the same segment during the few seconds it is the newest one. For a big broadcast that is exactly true, and it is why this is cheap. It stops being true in the long tail. A platform is not one enormous stream, it is thousands of small ones, and a channel with a handful of viewers scattered across the planet gives every edge a fan-out of one — each request a miss, each miss an origin fetch, and the CDN has become a proxy that charges you and adds a hop. So routing has to depend on how big an audience is, not only on who is nearest: collapse small streams onto far fewer PoPs so their viewers actually land together, and let the large events spread as wide as the map allows. The same thinning happens inside one stream once viewers rewind, which is why a DVR window never caches as well as the live edge does.

  • 1 fillper segment per edge
  • edgesserve the millions
  • tieredshield the origin

What the new pieces do

CDN Edgecache
Hundreds of edges caching segments near viewers, so one broadcaster can be served to millions cheaply.
Viewersclient
Millions of players fetching segments over HTTP, switching rendition up/down based on their measured bandwidth.

Step 6 · How live is "live"?

The latency dial

Standard HLS with 6s segments and buffering means viewers are often 15–30 seconds behind real time — fine for a movie premiere, painful for interactive streams where chat reacts to plays the streamer already made. How do you cut the delay?

BroadcasterIngestTranscoderPackagerOriginCDN EdgeViewers
The system as it stands at this step. · swipe to pan the diagram

Trade efficiency for latency deliberately. Shorter segments and smaller player buffers cut delay but add request overhead and rebuffer risk. Low-Latency HLS/DASH (chunked-transfer partial segments) gets you to ~2–5s while keeping CDN scalability. For true sub-second interactivity (auctions, betting, some Twitch modes) fall back to WebRTC-based delivery — at higher cost and less scale. Pick the point on the dial the product needs; you can even offer different latencies to different viewers.

Why this piece earns its place

Be precise about who pays when you turn this dial down, because it is not the platform. Most of that delay is the player’s buffer, and the buffer is the only thing absorbing a jittery network — those seconds are what let a phone on a train miss a segment, retry, and show the viewer nothing unusual. Spend the buffer and the median viewer notices nothing, because they have bandwidth to spare, while the worst-connected slice of the audience converts your improvement straight into rebuffering, which is a far worse experience than being behind. So I would set this against the rebuffer rate of the weakest decile rather than the average, and treat a move from standard HLS to a low-latency mode as a rollout to be measured, not a switch to be flipped globally. And because the right number is a product decision rather than a network fact, it is entirely reasonable to hand a tight profile to the viewers who need it and a deeper buffer to the ones who are struggling.

  • ~15–30sstandard HLS
  • ~2–5slow-latency HLS
  • <1sWebRTC (costly)

Step 7 · The other half of "live"

Chat, reactions & counts

A live stream isn't just video — it's the real-time interaction around it: chat scrolling, reactions, viewer counts, the streamer responding. That's a different, genuinely low-latency, fan-out problem running alongside the video.

CDN Edgegeo · tieredViewersABR playbackLive Chatrealtime
New in this step: Live Chat.

Run live chat as a separate real-time system: viewers connect over WebSockets to chat servers, and messages fan out to everyone in the channel (the same fan-out challenge as a chat app, at broadcast scale — often sharded by channel with a pub/sub backbone). Show a live viewer count (an approximate distributed counter). Keep chat and video as independent pipelines — chat is small and must be snappy; video is huge and CDN-served — so each scales on its own.

Why this piece earns its place

Decoupling the pipelines is right, and it creates one problem that lives entirely in the seam: chat arrives in real time while video arrives late, so the chat pane spoils the stream it sits beside. On standard HLS that is 15–30s of people reacting to a play the viewer has not been shown yet, and it is worse than it sounds, because two viewers on different renditions with different buffers are not even behind by the same amount. A single global delay on the chat service cannot fix that. The fix belongs on the client: stamp each message with the broadcast position it was sent at rather than with wall-clock time, and have the player withhold it until its own playback reaches that position. Every viewer then reads chat in step with the video they are actually watching, at the cost of a pane that is no longer strictly live — and it makes explicit that the streamer, who sits nearest the front, is answering questions about a moment the audience is only now reaching.

What the new pieces do

Live Chatclient
The parallel real-time layer — chat, reactions, viewer counts — fanned out over WebSockets alongside the video.

Step 8 · The sharp edges

Herds, DVR, geo & failure

Real broadcasts bring spikes and demands: a huge event starts and everyone hits play at once (a thundering herd), viewers want to rewind (DVR) or watch the replay (VOD), and the audience is global.

BroadcasterIngestTranscoderPackagerOriginCDN EdgeViewersLive Chat
The system as it stands at this step. · swipe to pan the diagram

Absorb the herd with CDN tiered caching and request coalescing (many edge misses for the first segment collapse into one origin fetch). Offer DVR by keeping a rolling window of past segments addressable, and produce VOD by retaining and re-packaging the segments after the stream ends. Go geo-distributed (regional ingest + CDN PoPs) so both broadcaster and viewers hit nearby infrastructure. Handle broadcaster disconnects gracefully (buffer/reconnect), and monitor rebuffer ratio and startup time as your core quality metrics.

Why this piece earns its place

Worth flagging what those two quality metrics imply, because rebuffer ratio and startup time are the only numbers here that describe the actual product, and no server can see either one. Origin and edge logs show segments handed over successfully, and a 200 on a segment reads exactly the same whether the player drew that frame on time or the viewer spent those seconds staring at a spinner. The rendition sits in the URL, so the logs can tell you which rung a player is on — what they can never tell you is why it chose that rung, or what the choice cost the person watching. Every failure that matters — the stall, the slow first frame, the player that gave up before the first frame ever arrived — happens after the last byte your infrastructure knows about. So playback quality has to be reported by the player, which makes the telemetry path its own fan-in from millions of clients back toward you, and therefore something to sample rather than collect whole. Sample it with dimensions attached — edge, region, rendition, device — because the aggregate is close to useless: a broadcast reads as healthy on average while one PoP is broken for everyone behind it, and dimensions are the only way that ever becomes visible.

You did it

You just designed a live streaming system.

BroadcasterIngestTranscoderPackagerOriginCDN EdgeViewersLive Chat
The finished design, end to end. · swipe to pan the diagram

Everything you assembled, in order

  • Live streaming is one-to-millions, latency-tolerant — optimize for cheap CDN fan-out, not sub-150ms.
  • Ingest accepts one broadcaster push (RTMP/SRT/WebRTC) — the cheap, few-sources side.
  • Transcode the source into an adaptive bitrate ladder so every device/network gets a smooth stream.
  • Segment each rendition into short HTTP chunks + a manifest (HLS/DASH) — video becomes cacheable files.
  • A CDN fans those segments out to millions; the origin serves only ~one fill per segment per edge.
  • The latency dial (standard HLS ~15-30s → LL-HLS ~2-5s → WebRTC <1s) trades delay vs scale vs cost.
  • Live chat is a separate WebSocket fan-out pipeline; DVR/VOD reuse the same segments.

Where an interviewer pokes next

Getting the boxes right is the easy half. These are the questions that separate a candidate who drew the diagram from one who has run the thing. Answer each one out loud before you open it.

  1. Why not use WebRTC (video-call tech) for a million-viewer live stream?

    Because a broadcast and a call are opposite shapes. A video call is few-to-few and needs sub-150ms latency so people can converse, which justifies expensive per-peer real-time connections through an SFU. A live stream is one-to-millions where viewers only consume media (they never send) and can comfortably tolerate a few seconds of delay. That latency tolerance is the key that unlocks a completely different, far cheaper architecture: instead of maintaining millions of real-time media connections, you turn the live video into small cacheable HTTP segments and let a CDN — built precisely to fan cacheable files out to huge audiences — do the distribution. WebRTC to a million viewers would be enormously expensive and operationally hard to scale, and you'd be paying for ultra-low latency the use case doesn't need. So mainstream live streaming (Twitch, YouTube Live) trades a few seconds of latency for essentially unlimited, cheap scale via HTTP/CDN, and only reaches for WebRTC when true sub-second interactivity is required.

  2. What does turning live video into HLS/DASH segments actually buy you?

    It converts an inherently un-cacheable thing — a continuous live stream — into a rolling series of ordinary, cacheable HTTP files, which lets you reuse the entire global HTTP caching infrastructure to scale. Concretely, each rendition is chopped into short segments (a few seconds each) that are numbered and listed in a manifest/playlist; the player fetches the manifest, then downloads segments over plain HTTP and plays them back-to-back, re-fetching the manifest to discover new segments as the broadcast continues. Because each segment is just a static file with a URL, a CDN can cache it at the edge exactly like an image or script: the first viewer on an edge triggers a cache-fill from origin, and every subsequent viewer on that edge is served the cached copy. This is what makes one-to-millions fan-out affordable — the origin serves roughly one fill per segment per edge while the CDN's hundreds of edges serve the actual millions. It also means DVR (keep recent segments addressable) and VOD (retain and re-package segments after the stream) nearly fall out of the same pipeline for free.

  3. How does the bitrate ladder plus ABR serve every device from one upload?

    The broadcaster uploads a single high-quality stream, but viewers span 4K TVs on fast connections and phones on a megabit of mobile data, so a one-size stream either buffers the phone or looks terrible on the TV. The platform solves this by transcoding the incoming source into a ladder of renditions at different resolutions and bitrates (for example 1080p, 720p, 480p, 360p, plus audio-only), all segmented and listed in the manifest. The player then performs adaptive bitrate streaming: it continuously measures its own throughput and buffer health and picks the highest rendition it can sustain, switching down when the network dips (so it keeps playing at lower quality instead of freezing) and back up when conditions improve. Because the transcoding is done centrally and per-broadcaster — of which there are relatively few — the cost is manageable, and the viewer side stays simple: just fetch whichever rendition's segments currently fit. One upload becomes a menu of qualities, one rung per network condition.

  4. Why is the CDN the thing that actually makes live streaming scale?

    Because the hard part of one-to-millions is fan-out, and once the video is expressed as cacheable HTTP segments, fan-out becomes a solved problem that the CDN already handles. Without a CDN, a million viewers pulling segments from your origin would saturate it instantly. With a CDN, viewers fetch from a nearby edge; the first request for a given segment at an edge is a cache miss that pulls once from origin, and the next thousands of viewers on that edge are all served the cached copy as hits. Multiply that across hundreds of edges and the origin only ever sees on the order of one fill per segment per edge, while the edges collectively serve the entire audience. Tiered/shield caches and request coalescing further protect the origin during the initial burst by collapsing many simultaneous edge misses for the same fresh segment into a single origin fetch. So the whole architecture — transcode, then segment — exists largely to hand the scaling problem to the CDN, which is why live streaming is fundamentally a clever application of CDN caching.

  5. What is the latency-vs-scale tradeoff and how do you choose where to sit?

    Latency and cheap scale pull in opposite directions in live video, and the delivery method is the dial. Standard HLS/DASH with multi-second segments and a safety buffer is the most scalable and cheapest — it rides ordinary CDN caching to reach millions — but viewers end up roughly 15–30 seconds behind real time, which is fine for a concert or premiere but bad when chat reacts to a play the streamer already made. Low-Latency HLS/DASH uses techniques like chunked transfer of partial segments to cut the delay to about 2–5 seconds while still being CDN-cacheable, at the cost of more complexity and tighter operational tolerances. For genuine sub-second interactivity — live auctions, betting, tightly interactive streams — you fall back to WebRTC-based delivery, which achieves near-real-time latency but is far more expensive and harder to scale to huge audiences. You choose based on the product's interactivity needs and budget, accepting more cost/complexity only where low latency genuinely matters, and platforms sometimes even serve different latency tiers to different viewers of the same event.

Check yourself — the answers, and why

Nine steps in, these are the calls you should be able to make cold. Pick one, then read why.

  1. Live streaming optimizes for cheap CDN fan-out (not sub-150ms) because…

    Latency tolerance lets you turn video into cacheable files a CDN fans out to millions.

  2. Transcoding into a bitrate ladder exists so that…

    One upload becomes many qualities; the player adapts up/down to its bandwidth.

  3. Segmenting into HLS/DASH chunks matters because…

    Numbered segments + a manifest make live video indistinguishable from static files to a CDN.

  4. One broadcaster reaches a million viewers without melting the origin because…

    Cacheable segments let the CDN's edge fan-out and tiered shields absorb the crowd.

  5. The biggest architectural knob in live streaming is…

    Lower latency costs scale and money; pick the point per use case.

How you’d open this design in an interview

Before any boxes: agree what it must do, pin the qualities that shape everything, then build — naming each trade-off as you make it. The walkthrough above is that exact order.

What it must do

Agree on these before drawing a single box.

  • Ingest: accept one broadcaster’s push over RTMP/SRT/WebRTC and authenticate the stream key.
  • Transcode: re-encode the source into an adaptive bitrate ladder (1080p/720p/480p/360p) so every device fits.
  • Package: segment each rendition into short HLS/DASH chunks + a manifest — cacheable HTTP files.
  • Fan out: deliver segments to millions of viewers through a CDN, not from the origin directly.
  • Interact: live chat, reactions and viewer counts alongside the video; DVR rewind and VOD replay.

The qualities that shape everything

Each one names the mechanism that buys it.

Fan one stream out to millions cheaply
Segment the video into ordinary cacheable HTTP files so a CDN’s edges serve the crowd — the origin does only ~one cache-fill per segment per edge.
Every device and network gets a smooth stream
Transcode the source into an adaptive bitrate ladder; the player runs ABR, dropping to a lower rendition instead of buffering when bandwidth dips.
Scale beats sub-second latency (the right trade)
Viewers only consume and tolerate a few seconds of delay, so you optimize for cheap HTTP/CDN fan-out rather than per-viewer real-time connections.
Reliable, continuous ingest from the broadcaster
An ingest endpoint accepts the push over RTMP/SRT/WebRTC, authenticates the stream key, and handles reconnects — the cheap, few-sources side.
Choose how “live” live is
The latency dial — standard HLS ~15–30s, LL-HLS ~2–5s, WebRTC <1s — trades delay against scale and cost per use case.
Interaction stays snappy without dragging on video
Run live chat as a separate real-time WebSocket fan-out pipeline, independent of the CDN-served video so each scales on its own.

The trade-offs you say out loud

Senior signal isn’t the boxes — it’s naming what you gave up and why it was the right price.

HTTP/CDN segment streaming over WebRTC to every viewer

WebRTC gives sub-150ms to a few peers at high per-connection cost — needless when viewers only consume and tolerate a few seconds. Cacheable HTTP segments let a CDN fan out to millions cheaply.

Central transcode into a ladder over broadcasters uploading every quality

Broadcasters have limited upload bandwidth and can’t send many renditions at once; transcoding centrally means one upload becomes every quality the player’s ABR can pick from.

HLS/DASH segments + manifest over one long-lived stream per viewer

CDNs aren’t built to fan out millions of persistent live streams; chopping each rendition into numbered HTTP files makes live video cacheable like any static asset, so the CDN absorbs the crowd.

Separate chat and video pipelines over one unified real-time pipeline

Video is huge, cacheable and seconds-latency; chat is small and must be snappy. Coupling them would drag chat down to video’s latency or push video up to chat’s cost — keep them independent.

The answer, out loud

What a strong answer to “Design a Live Streaming System” sounds like, first question to last trade-off. It is about 7 minutes of talking; the whiteboard and the interviewer fill the rest of the 45. Read it aloud once, then close the page and give it yourself.

  1. 0–3 min

    Scope it before drawing anything

    Let me pin down what we’re building. One broadcaster is pushing video up, and a lot of people should be watching it at roughly the same time, on phones and TVs and laptops, on every kind of network, anywhere in the world. The thing I want to establish first is what that audience actually needs, because it decides everything after it. They are watching, not talking back, and they won’t notice a few seconds of delay as long as the picture doesn’t stop. So my target is smooth playback at very large scale and a low cost per viewer, and I’m deliberately not chasing real time.

  2. 3–8 min

    Why this isn’t a video call

    The first fork is whether to reuse video-call technology, and I’d say no. A call is a few people who all have to be within about a hundred and fifty milliseconds of each other, and you pay for that with a live connection per participant. Here nobody is talking back, so that cost buys me nothing and it multiplies by the size of the audience. The delay tolerance is the opening: if a viewer can sit a few seconds behind, I can put the video somewhere and let them come and fetch it — and fetching is something the internet is already very good at scaling.

    Built in step 1: One-to-millions, not few-to-few
  3. 8–13 min

    The broadcaster side is the small side

    Ingest is the easy end, and I want to say why out loud: there are very few broadcasters and enormous numbers of viewers, so the two sides deserve completely different technology. Broadcasters push, over RTMP or SRT or WebRTC depending on how lossy their uplink is, into an endpoint that checks their stream key and hands the stream onward. That’s a per-broadcaster cost and it’s small. Every hard scaling decision I make from here lives on the other side of that box.

    Built in step 2: Ingest
  4. 13–20 min

    One upload, many qualities

    Next problem. The broadcaster sends one quality — say 1080p at six megabits — and part of the audience is on a phone with about a megabit. Send everyone the source and the phone never plays; send everyone the small version and the TV looks awful. I wouldn’t push this back onto the broadcaster, because their upload is the scarce resource: they can send one stream well, not four. So I transcode centrally into a ladder, 1080p down through 360p, and let the player choose. It measures its own throughput and moves between rungs, so a wifi dip turns into a quality dip instead of a freeze.

    Built in step 3: Transcoding into a bitrate ladder
  5. 20–27 min

    Stop producing a stream

    Now the move the whole design turns on. A continuous stream isn’t something a cache can hold, so I stop producing one. The packager chops every rendition into short chunks of a few seconds, numbers them, and writes a manifest listing them, appending as the broadcast goes on. The player reads the manifest, pulls chunks over ordinary HTTP, and plays them end to end. Nothing about that looks like video to the network any more — it’s a rolling set of small static files, which is the one thing the internet already delivers to huge audiences for almost nothing.

    Built in step 4: Segment into HTTP chunks
  6. 27–34 min

    Let the CDN do the fan-out

    Which is the point of doing it. I put a CDN in front of the origin and viewers fetch from an edge near them. The first person on an edge to ask for a chunk causes one fetch back to origin; everyone else on that edge gets the copy already sitting there. Multiply that across hundreds of edges and my origin is doing about one fill per chunk per edge however many people are watching, with shield caches in front of it for the opening burst. The audience scales on infrastructure I didn’t have to build.

    Built in step 5: CDN fan-out
  7. 34–39 min

    How live is live

    I’d expect to be asked how live this actually is, and I’d present it as a dial rather than a fixed answer. Plain HLS with comfortable chunks and buffers puts people roughly fifteen to thirty seconds back, which is fine for a premiere and bad for anything the audience is reacting to. Low-latency HLS brings that to a few seconds and still rides the same caching. Genuinely under a second means going back to WebRTC delivery, which costs much more and scales much less. I’d pick per product, and I wouldn’t buy a number the product can’t use.

    Built in step 6: The latency dial
  8. 39–43 min

    The rest of the experience

    The last piece is that a stream isn’t only video. Chat, reactions and the viewer count are a separate real-time system over WebSockets, sharded by channel, and I want it separate on purpose — it’s tiny and has to be fast, whereas the video is enormous and is allowed to be late. Wiring them together would drag one of them to the other’s worst property. Rewind and replay come almost free, because I already have the chunks: keep a window of them and that’s DVR, keep all of them and repackage and that’s the replay.

    Built in step 7: Chat, reactions & counts
  9. 43–45 min

    The trade, and what I’d do next

    So the shape is one push in, a ladder out, chunks and a manifest, a CDN doing the fan-out, and chat running beside it. The trade I made on purpose is delay for reach — viewers sit seconds behind so that each additional one costs almost nothing. With more time I’d spend it on going geo-distributed, so a broadcaster on another continent isn’t pushing across the planet before the pipeline even starts, and on the opening minute of a big event, where everyone presses play at once and the very first chunk is the one request the cache has never seen.

What this teaches

Learn system design by building a live video streaming system like Twitch or YouTube Live step by step. An interactive guide covering ingest of a broadcaster stream, transcoding into an adaptive bitrate ladder, segmenting into HLS/DASH chunks, CDN fan-out to millions of viewers, the latency-vs-scale tradeoff, live chat, DVR/VOD, and the unhappy paths (thundering herd, low-latency modes, geo-distribution).

Key takeaways

  • Live streaming is one-to-millions, latency-tolerant — optimize for cheap CDN fan-out, not sub-150ms.
  • Ingest accepts one broadcaster push (RTMP/SRT/WebRTC) — the cheap, few-sources side.
  • Transcode the source into an adaptive bitrate ladder so every device/network gets a smooth stream.
  • Segment each rendition into short HTTP chunks + a manifest (HLS/DASH) — video becomes cacheable files.
  • A CDN fans those segments out to millions; the origin serves only ~one fill per segment per edge.
  • The latency dial (standard HLS ~15-30s → LL-HLS ~2-5s → WebRTC <1s) trades delay vs scale vs cost.
  • Live chat is a separate WebSocket fan-out pipeline; DVR/VOD reuse the same segments.

Concepts covered

  • What makes live streaming hard?
  • One-to-millions, not few-to-few
  • Ingest
  • Transcoding into a bitrate ladder
  • Segment into HTTP chunks
  • CDN fan-out
  • The latency dial
  • Chat, reactions & counts
  • Herds, DVR, geo & failure
built to fan one broadcaster out to a million screens — make the calls, drop the CDN, run the gauntlet.
Finished this one? 0 / 65 System Designs done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More System Designs