ML Systems Review

Figma's Multiplayer Cursor Sync: A 2026 Architecture Update

Three years after our first teardown of Figma's CRDT stack, the company has shipped a WebRTC-plus-CRDT hybrid. Median cursor latency is down. The conflict rules have changed. Here is what is new.

Distributed Systems
By Priya Ramachandran , MS Reviewed by Dr. Nadia Volkov , PhD
9 min read
TL;DR

Figma's 2026 multiplayer update keeps its per-object CRDT core but offloads cursor telemetry and ephemeral selection state to a WebRTC data-channel mesh, mediated by a SFU-style coordinator. Median cursor latency on the same continent is now roughly 38 ms, down from a reported 85 ms in 2023. The conflict-resolution heuristic for text nodes now uses a modified Logoot ordering with explicit tie-breaking on authorship recency.

When Figma first published details of its multiplayer engine in 2019, the design — a per-property CRDT stored on a central server, with a websocket broadcast fanout — was notable mostly because nobody else in the design-tool space had bothered. Seven years later, Figma's concurrency model is still the reference implementation, but it is no longer the one from 2019. The 2026 update, confirmed in a staff engineering talk at QCon London and corroborated by two former infrastructure engineers on background, splits transport in two: durable state continues to flow through the original CRDT path, while ephemeral state — cursor positions, selection rectangles, hover highlights — moves to a WebRTC data-channel mesh.

This is a follow-up to our 2023 analysis, "CRDTs in production: lessons from Figma's multiplayer engine", which covered the server-authoritative design in its earlier form. Readers who want the fundamentals — why Figma uses a CRDT per property rather than operational transform, how the document tree is decomposed, how lamport clocks are stamped — should start there. This piece is narrower: what changed in 2026 and why.

What the 2026 update actually is

The publicly observable change, visible from any developer-tools network tab, is that a Figma document now opens two distinct connections instead of one. The primary connection is the familiar websocket to a Figma multiplayer server, terminating at a per-document shard. The secondary connection is a WebRTC data channel, negotiated through an ICE/STUN handshake and — in the common case, when peer-to-peer traversal succeeds — carrying traffic directly between clients without touching a Figma-owned server.

The division of labour, according to the QCon talk, is strict. The websocket carries "durable" edits: creation and deletion of nodes, property mutations that survive a reload, comments, prototyping state. The data channel carries "ephemeral" state: cursor coordinates, selection rectangles, text-tool placement, and the live preview of a drag that has not yet been committed. Anything that needs to persist to the document is a CRDT op on the websocket; anything that exists only while the browser tab is open is a WebRTC message.

┌─────────────┐ ┌───────────────────┐ ┌─────────────┐ │ Client A │◀── WSS ───▶│ Figma multiplex │◀── WSS ───▶│ Client B │ │ │ │ (CRDT authority) │ │ │ │ │ └───────────────────┘ │ │ │ │ ▲ │ │ │ │ │ ICE/STUN signalling │ │ │ │ │ │ │ │ │◀═══ WebRTC data channel (peer-to-peer) ═══▶│ │ └─────────────┘ └─────────────┘ solid = durable CRDT state (document mutations, comments) double = ephemeral state (cursor, selection, live drag)

Figure 1. Figma's 2026 two-channel transport split. Durable mutations still route through the websocket fabric; cursor and selection state uses a WebRTC mesh with the multiplex server only as ICE signalling.

Why the split

The motivation is latency, but the reason latency matters is subtle. For a single mutation — dragging a rectangle ten pixels — the round trip to a Figma server in us-east-1 from a client in California was, in 2023, about 85 ms. That is fine for most interactions. The problem is cursor updates at 60 Hz. A cursor emitting sixteen frames per 100 ms, each with an RTT of 85 ms, produces a visible lag between the pointer motion a remote user sees and the actual pointer position. On a shared canvas with four or five collaborators, the aggregate perception is of pointers that "swim" behind their owners.

An engineer on the Figma platform team, speaking on background in December, described the internal metric as "perceived sync": the delta between a user's cursor position and the rendered cursor position on a peer's screen. The 2024 perceived-sync median on the same continent was 85 ms; the 2026 median is 38 ms. Inter-continental links — San Francisco to Frankfurt, say — dropped from about 170 ms to roughly 95 ms, not because the speed of light changed, but because the WebRTC path avoids a hairpin through the US-east regional multiplexer.

The second motivation, less emphasised in the QCon talk but visible in Figma's status-page history, is congestion control. Cursor telemetry is an N-squared problem: ten people in a document produce a hundred cursor-to-peer messages per tick. Fanning that through a single websocket server means the server has to copy and send all hundred messages. Moving this traffic to peer-to-peer is a fan-out reduction from O(N²) on the server to O(N) on each client, which is a dramatic load drop at the document-sharding tier.

The SFU-style coordinator

Peer-to-peer WebRTC in the real world rarely works peer-to-peer. NAT traversal fails often enough — by Google's own published numbers, about 8% of connections — that any production WebRTC system needs a fallback. Figma's fallback, according to three sources familiar with the architecture, is an SFU-style coordinator: a small forwarding server that receives WebRTC streams from peers that cannot reach each other and forwards them on the same data-channel protocol. The coordinator does not process the payloads; it is a pure relay.

The SFU approach, borrowed from videoconferencing (Jitsi, LiveKit, and Google Meet all use variants of it), keeps the ephemeral-state protocol uniform from the client's perspective. The client always sends cursor updates over a data channel. Whether that channel terminates at another browser or at a Figma SFU is invisible above the transport layer. This is, in our experience, the cleanest way to ship WebRTC to a general consumer audience — the alternative, exposing peer-to-peer failures to the application layer, tends to produce a long tail of bug reports that are expensive to diagnose.

Conflict resolution: what actually changed

The 2019 Figma CRDT used a straightforward last-writer-wins policy per property, with ties broken by client ID. For scalar properties — position, fill colour, font size — this works fine and has not changed. For text content, however, the 2019 design used a Logoot-style sequence CRDT with lamport timestamps on each character, and the tie-breaking rule was the client ID. This produced a subtle failure mode: in rare concurrent-edit scenarios, a typed character from a lower-client-ID client would lose to an older character from a higher-client-ID client, producing text that looked correctly ordered on one screen and garbled on another.

The 2026 update replaces the client-ID tie-breaker with an authorship-recency heuristic. The rule, as described at QCon, is that when two character insertions have identical lamport positions, the one with the more recent session start wins. The intuition is that a user who just joined the document and started typing is more likely to have intentionally placed a character at a specific location than a user whose session is hours old and whose cursor might be stale. An engineer on the text-editing team described this as "an improvement of a few tenths of a percent" in observable text conflicts — small on paper, but text CRDTs produce user-visible corruption when they misbehave, and the team had been chasing these edge cases since 2022.

// 2019 tie-breaker if (op_a.lamport == op_b.lamport) { winner = (op_a.client_id > op_b.client_id) ? op_a : op_b } // 2026 tie-breaker if (op_a.lamport == op_b.lamport) { winner = (op_a.session_start > op_b.session_start) ? op_a : op_b // older session loses, fresher session wins }

Figure 2. Tie-breaking rule change between the 2019 and 2026 Figma text CRDT implementations. The 2019 rule used client ID; the 2026 rule prefers the more recently started session.

Observable performance numbers

We reproduced a small benchmark against a shared Figma file from three geographic locations (San Francisco, Frankfurt, Singapore) over a week in December 2025 and January 2026. The methodology was crude: a browser-side timestamp captured on cursor emit, matched against a peer-side timestamp on cursor render, corrected for client clock skew using an NTP-synchronised offset measured hourly.

Route 2023 median (ms) 2026 median (ms) Delta
SF ↔ SF8538−55%
SF ↔ Frankfurt17294−45%
SF ↔ Singapore238161−32%
Frankfurt ↔ Frankfurt7935−56%

The pattern is what a transport-layer change would predict: larger relative improvements on same-region routes (where WebRTC has a short physical path and the multiplex hairpin was the dominant cost), smaller improvements on trans-Pacific routes (where physical latency dominates no matter what the transport looks like).

What did not change

The document CRDT itself is unchanged, or at least indistinguishable from the 2019 design at our level of observation. The document tree decomposition into per-property CRDTs, the websocket-based fanout, the shard-per-document authority model — all of this still holds. Comments, prototyping links, and component libraries remain on the durable path. A user on a slow connection whose WebRTC handshake fails gets a slower cursor but the same editing experience.

This is the right architectural instinct. The durable state is where bugs are expensive (a lost edit is worse than a janky cursor) and where the investment in CRDT correctness pays off. The ephemeral state is where latency is the dominant concern and a lost packet is invisible the next tick. Using different transports for different failure tolerances is a pattern we expect to see more of in 2026 and 2027, particularly as browsers' WebTransport support matures. Figma is early on that curve, not at the end of it.

Open questions

Three things about the 2026 architecture are unclear from public materials. First, the SFU fallback rate: how often are peers actually talking to a Figma SFU rather than to each other? Figma has not published this and it matters for capacity planning. Second, encryption: WebRTC data channels are DTLS-encrypted by default, but the key-exchange ceremony for large documents (fifty-plus collaborators) is expensive, and it is not clear how Figma amortises this. Third, the authorship-recency tie-breaker is a heuristic, not a formally verified policy; we would like to see the team publish the invariant it preserves, the way the original 2019 design was accompanied by a correctness argument.

None of these are reasons to doubt the update. They are the questions we would ask if we were on the team's technical-review board.

Further reading

Corrections to this piece go to corrections@mlsystemsreview.com. Figma declined to comment on the record; the engineers quoted on background are named in our internal notes and verified by one editor.