If you arrived here from the business version, you're in the right place. That piece covered what scaling past a single media server costs, and why the bill grows with the square of the room. This is the companion "how" — where the bottleneck actually sits at each stage, and what changes when you add the second box.

SFU scaling has a reputation for being a single wall you hit at some participant count. It isn't. The bottleneck moves three times before you genuinely run out of machine, and each move changes which metric is worth watching.

Most capacity problems in production are not a shortage of capacity. They are a team watching the limit they hit last time.

First, the unit: SFU scaling is counted in consumers

An SFU does not forward participants. It forwards streams, and the working unit is the consumer — one outbound stream to one receiver. In a room where everyone subscribes to everyone, that is N x (N-1).

This is why participant counts are a poor capacity unit. A room of seven generates 42 consumers. A room of seventy generates 4,830. Same server, same software, 115x the work — and any figure quoted in participants has silently baked in an assumption about room shape that almost certainly does not match yours.

With the unit fixed, the three limits line up in order.

Bottleneck 1: the worker process, and why it is one core

Most SFUs run their media path as single-threaded workers, one per CPU core. mediasoup is explicit about this in its own documentation: a worker subprocess handles "over ~500 consumers," and scaling within a host means running more workers and distributing routers across them.

The per-consumer cost is small but real. For each outbound stream the server terminates and re-applies SRTP, rewrites RTP sequence numbers and timestamps, tracks RTCP feedback, and maintains per-consumer state for retransmission and layer selection. None of it is transcoding — that is the whole point of an SFU — but at a few thousand streams the accounting itself becomes the workload.

What this means practically: a single worker saturates at about 23 participants in one all-see-all room, because 23 x 22 = 506. That is a much smaller number than most teams expect, and it is the reason a 16-core box does not behave like one big server unless your rooms are distributed across its workers deliberately.

The fix inside one host is routing, not hardware. Pin rooms to workers, and use the SFU's own inter-router piping when a single room needs more than one worker. Get that wrong and you have fifteen idle cores and one saturated one.

Solve the worker problem and the next limit is already waiting, usually closer than expected.

Bottleneck 2: the network interface

Egress saturates sooner than CPU in most real deployments, and it is the limit teams model least.

Work it through. A 40-person room at an average 600 kbps per forwarded stream — a realistic figure when simulcast is on and most grid tiles receive a lower spatial layer — is 1,560 x 600 kbps, or 936 Mbps. That is one room, one machine, and effectively a full gigabit link.

The independent IPTComm benchmark of Jitsi, Janus, Medooze and Kurento is a useful sanity check here. It ran on a 16-vCPU instance with 2 Gbps of dedicated network and topped out around 490 participants in rooms of seven — a configuration that is deliberately egress-light, since rooms of seven generate only 42 consumers each. Put those same 490 people into one room and you would need 239,610 consumers. The hardware was never the variable.

Two design consequences follow. First, NIC capacity and not core count should drive instance selection for large rooms. Second, average forwarded bitrate is the single highest-leverage number in the whole system, because it is multiplied by N x (N-1) — shaving 100 kbps off the average saves 156 Mbps in a 40-person room. What that traffic costs depends entirely on where you host it.

When one machine's interface is full, you add a second machine. That is where SFU scaling stops being arithmetic and becomes topology.

Bottleneck 3: the cascade mesh — and why SFU scaling across boxes is cheaper than it looks

Cascading splits a room across servers. Participants connect to whichever server is closest or least loaded, and the servers forward published streams to each other so everyone can still subscribe to everyone.

The common fear is that inter-server traffic explodes. It doesn't — provided the cascade sends one copy of each published stream per server, rather than one copy per remote subscriber. That distinction is the whole design.

Take a 70-person room. On one server that is 4,830 consumers. Split across two servers with 35 participants each:

Topology

Egress per server

Inter-server traffic

Total streams out

1 server, 70 users

4,830

4,830

2 servers, 35 each

2,450

35 streams each way

4,900

3 servers, ~23 each

1,633

46 streams per server

4,899

Total traffic rises by about 1.4%. Per-server load halves with two boxes and drops to roughly a third with three. The inter-server term stays almost flat because it scales with publishers and servers, not with subscribers — 35 streams crossing between two servers, versus 2,450 going out to clients.

So cascading is close to free in bandwidth terms. What it actually costs you is elsewhere:

  • Placement logic. Which participant lands on which server, and what happens when the answer changes mid-call.
  • Failure domains. One server dying no longer ends the call — it partially ends it, for some participants, which is a harder state to handle than a clean failure.
  • Added latency on the cross-server hop, which matters for interactive use and compounds with geographic distribution.
  • Layer selection across the boundary, since the remote server has to decide which simulcast layer to pull without seeing the subscriber's bandwidth estimate directly.

That last point is where a lot of quality regressions come from, and it is worth checking what your SFU does before assuming the behaviour. Cascading in a production surveillance deployment across 50 sites shows the pattern working at scale.

Which brings up the harder question: how do you know when any of this is going wrong?

What the load tests actually measured

The IPTComm study produced one finding that is more useful than its headline numbers: bitrate and round-trip time are poor proxies for video quality.

Across the runs, bitrate and RTT both degraded noticeably at around 250 participants, while perceived video quality — scored with a dedicated video quality algorithm rather than inferred — held up until per-stream bandwidth dropped below roughly 200 kbps. The metrics that were easy to collect moved first; the metric that mattered moved later. Worth noting that the same study recorded Jitsi reaching its 490-participant target with a 79% video-check failure rate, which is the sharpest possible illustration of the same point.

That asymmetry cuts both ways. It means an alert threshold set on bitrate or RTT will fire before anything is actually wrong, which trains teams to ignore it. And it means that by the time the ignored alert would have been correct, the useful warning window has already passed.

For SFU scaling specifically, the metrics worth alerting on are the ones with a hard ceiling: consumer count per worker, sustained egress against NIC capacity, and the rate of layer downgrades the server is issuing. The third is the closest thing to an early warning the system produces, because bandwidth estimation reacts before users do.

Some of the levers that change all three numbers are routing decisions rather than capacity decisions.

Routing decisions that change the arithmetic

Two mechanisms alter the consumer count directly, and both are worth deliberate configuration rather than defaults.

Simulcast lets the SFU choose which spatial layer to forward per subscriber. Publishing three layers costs the sender roughly 20% more uplink — a 720p/360p/180p ladder is about 3.0 Mbps against 2.5 Mbps for the top layer alone, because bitrate scales with pixel count and the lower layers are small. In exchange, the server can send a 180p stream to a thumbnail tile instead of 720p, which is where the average forwarded bitrate in the egress math above comes from. The real cost of simulcast is not bandwidth; it is three parallel encodes on the publisher, which is the binding constraint on mobile.

Speaker-based forwarding cuts the consumer count outright. If the client only renders the nine most recent speakers, the server has no reason to forward seventy streams to it. This turns N x (N-1) into something closer to N x k, which changes the growth curve from quadratic to linear and is by far the largest single lever available. It also introduces switching artefacts and a dependency on speaker detection being right, so it is a UX decision as much as an infrastructure one.

Between them, these two decide whether a large room is a capacity problem at all.

Build, Buy, or Deploy

Three routes, with the honest boundary on each.

Build on open source

mediasoup, Janus, Pion and LiveKit are all production-grade, and the benchmark numbers in this post come from exactly this class of software. Building gives you full control over placement, layer selection and cascade behaviour, which is genuinely valuable if your room shapes are unusual. The cost is that everything in the Bottleneck 3 list becomes yours to design, and cascade failure handling in particular is a deep piece of work that is easy to underestimate.

Buy a cloud video API

Per-minute providers hide all three bottlenecks entirely, which is the right trade at low or unpredictable volume. The limits are that you inherit their placement and layer-selection policy, you generally cannot see the consumer-level metrics discussed above, and per-minute pricing is linear in participants while your traffic is quadratic in room size — so large rooms are where the model fits worst.

Deploy a commercial platform

The middle path runs a commercial platform on infrastructure you select. Samvyo is one such option: based on SFU architecture, shipping embeddable SDKs, with the media path, TURN and recording kept on infrastructure you control — which is what makes the egress and placement decisions above yours to make rather than a vendor's. It is resilient by design rather than something you assemble from parts.

Where it does not fit: if you need to modify forwarding behaviour at the source level, or your workload is small enough that none of these bottlenecks will ever bind, building or buying respectively will serve you better.

The Bottom Line

SFU scaling is three limits in sequence, not one. The worker caps at roughly 500 consumers per core, the network interface caps well below what most instance types suggest, and the cascade mesh — the one everyone worries about — turns out to add only a few percent to total traffic when implemented correctly.

Measure consumers rather than participants, watch egress rather than CPU, and treat layer selection and speaker-based forwarding as capacity decisions. They change the growth curve itself, which no amount of hardware does.

What's Next

The business companion, Scaling video cost: what happens when one media server isn't enough, prices the traffic this post describes — including the egress line that most self-hosting cost models leave out. For the foundation, what an SFU is and why every video platform uses one covers the basics.

Frequently Asked Questions

What is the main bottleneck in SFU scaling?

It moves. The worker process limits you first at roughly 500 consumers per CPU core, the network interface limits you second and usually sooner than teams expect, and the links between cascaded servers limit you third. Each stage needs a different metric, which is why capacity problems often look like a team monitoring the limit they hit previously.

How many consumers can one SFU worker handle?

Around 500, per mediasoup's own documentation, on one CPU core. That works out to about 23 participants in a single room where everyone sees everyone, since 23 x 22 is 506. Larger rooms need multiple workers with routers piped between them, or multiple hosts.

Does cascading SFUs increase total bandwidth usage?

Only marginally — around 1.4% in a 70-person room — provided the implementation sends one copy of each published stream per server rather than one per remote subscriber. Per-server load roughly halves with two servers. The real costs of cascading are placement logic, partial failure handling and the extra hop's latency, not bandwidth.

Should I scale an SFU vertically or horizontally?

Vertically until you hit the network interface, then horizontally. Adding cores helps only if rooms are distributed across workers deliberately, and it does nothing once egress is the constraint. A second machine adds a second NIC, which is usually the actual reason to add it.

Why is CPU low while my SFU is struggling?

Almost always egress saturation. Forwarding is cheap in CPU terms and expensive in bandwidth terms, so a server can be at 30% CPU with a completely full network interface. Check sustained outbound throughput against NIC capacity before adding cores.

What metrics should I alert on for SFU scaling?

Consumer count per worker, sustained egress against interface capacity, and the rate of simulcast layer downgrades the server is issuing. Independent benchmarking has shown that bitrate and round-trip time degrade well before perceived quality does, so alerts built on those two tend to fire early and get ignored.

Does simulcast reduce the load on the SFU?

It reduces egress, not CPU. The server forwards a lower spatial layer to subscribers who don't need full resolution, which cuts the average forwarded bitrate substantially in grid layouts. The consumer count is unchanged — the server still tracks per-subscriber state for every stream — so the worker limit still applies.