Figma is a browser-based collaborative design tool used by millions of designers, serving as a real-time multiplayer editor for vector graphics. Designing Figma tests your understanding of CRDTs for conflict-free collaboration, efficient vector rendering in the browser, component/asset management, and scaling real-time sync to thousands of concurrent editors. This is a unique system design question that combines graphics, real-time systems, and collaboration.
Document Data Model
A Figma file is a tree of nodes. Root: the file (canvas). Children: pages. Each page contains frames, groups, and primitives (rectangles, ellipses, text, vectors, images). Each node has: node_id (UUID), parent_id, type, position (x, y), dimensions (width, height), style properties (fill, stroke, opacity, effects), and type-specific data (text content, image reference, vector paths). The tree can be deep: a component instance inside a frame inside a page inside a file. With hundreds of frames and thousands of elements, a complex design file has 10,000-100,000 nodes. Storage: the document is stored as a serialized tree (Protocol Buffers or FlatBuffers for compact binary representation). On S3 for persistence. In memory on the collaboration server for real-time editing. Versioned: each save creates a new version. Figma auto-saves continuously (every few seconds of inactivity after changes). Version history allows restoring any previous state. Component library: reusable components (buttons, cards, icons) are nodes marked as “component.” Instances reference the component definition. Changing the component propagates to all instances. This is similar to inheritance in OOP — the instance inherits properties from the component but can override specific ones.
Real-Time Multiplayer Collaboration
Multiple designers edit the same file simultaneously. Every change (move a rectangle, change a color, add text) must be visible to all editors within 100ms. Figma uses a CRDT-inspired approach for conflict resolution (they call it “multiplayer”). Each operation is a property change on a node: set(node_id, property, value). Operations are identified by a logical timestamp (Lamport clock) and the author. Conflict resolution: last-writer-wins per property. If User A sets rectangle color to red and User B sets it to blue simultaneously, the one with the higher timestamp wins. This is simple and works well for design tools because: (1) Designers rarely edit the same property of the same element simultaneously. (2) When they do, either value is acceptable (there is no “merge” of two colors). Cursor/selection sharing: each user cursor position and selection are broadcast to all editors via the collaboration server. This is ephemeral state (not persisted). WebSocket connection: each editor maintains a WebSocket to the collaboration server. Operations are sent immediately on each change. The server broadcasts to all other editors of the same file. Latency target: under 100ms from edit to visibility on other screens.
Vector Rendering in the Browser
Figma renders complex vector graphics directly in the browser using WebGL (GPU-accelerated 2D rendering) via a custom rendering engine compiled to WebAssembly (Wasm). Why not SVG/Canvas 2D: (1) SVG: each element is a DOM node. With 10,000+ elements, the DOM becomes too large and slow. SVG also lacks efficient GPU utilization. (2) Canvas 2D: better than SVG for many elements but still CPU-rendered. Complex designs with blurs, shadows, and gradients are too slow. (3) WebGL + Wasm: the rendering engine (written in C++ compiled to Wasm) runs at near-native speed. WebGL uses the GPU for drawing. This handles 100,000+ elements with smooth 60fps panning and zooming. Rendering pipeline: the document tree is traversed. Each visible node is converted to GPU draw commands (textured quads, path tessellation). GPU batching minimizes draw calls. Culling: only visible elements (within the viewport) are rendered. Off-screen elements are skipped entirely. Level-of-detail: when zoomed out, small elements are simplified or hidden. Incremental rendering: on a property change (e.g., color), only the affected element and its overlapping elements are re-rendered. The rest of the frame is cached as a texture. This makes editing feel instant even on large files.
File Storage and Loading
A large Figma file can contain thousands of elements, hundreds of images, and complex vector paths. File size: 10-500 MB serialized. Loading the entire file before displaying anything would be too slow. Lazy loading: (1) Load the file metadata and page list immediately. (2) Load the current page elements. (3) Load images on demand (thumbnails first, full resolution when zoomed in). (4) Other pages are loaded in the background or when the user navigates to them. Image handling: images referenced in the design are stored separately in S3. The document stores an image reference (hash). When rendering: the client fetches the image from CDN by hash. Multiple uses of the same image share one stored copy (deduplication by content hash). Image optimization: Figma generates multiple resolutions per image. The client requests the appropriate resolution based on the current zoom level. At 10% zoom: a 100px thumbnail suffices. At 100% zoom: the full resolution is needed. Offline support (limited): Figma is browser-based with limited offline support. Recent files are cached in the browser (IndexedDB/Cache API). Edits made offline are queued and synced when connectivity returns. The CRDT model handles merging offline edits with concurrent changes from other users.
Scaling the Collaboration Server
Each file being actively edited runs on a collaboration server instance that holds the document state in memory. Scaling: (1) One server per file (or per set of files). When a user opens a file, the system assigns it to a collaboration server. All editors of the same file connect to the same server (required for consistent operation ordering). (2) Server assignment: a routing service maps file_id -> server_id. When a file is opened for the first time: pick a server with available capacity, load the file from S3 into memory, and register the mapping. Subsequent editors of the same file are routed to the same server. (3) Server capacity: each collaboration server handles 50-200 concurrent files depending on file size and editor count. With millions of files open concurrently: thousands of collaboration servers. (4) Failover: if a collaboration server crashes, its files are reassigned to other servers. The last persisted version is loaded from S3. Any unsaved changes since the last auto-save (up to a few seconds) may be lost. Editors are reconnected to the new server automatically. (5) Geographic distribution: collaboration servers are deployed in multiple regions. Users connect to the nearest region. For cross-region collaboration (a US designer and EU designer editing the same file): the file is hosted in one region, and the remote user experiences slightly higher latency (80-150ms vs 20ms local). This is acceptable for design collaboration.
{“@context”:”https://schema.org”,”@type”:”FAQPage”,”mainEntity”:[{“@type”:”Question”,”name”:”How does Figma achieve real-time multiplayer editing?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Figma uses a CRDT-inspired approach where each operation is a property change on a node: set(node_id, property, value). Conflicts use last-writer-wins per property — if two users change the same rectangle color simultaneously, the higher timestamp wins. This works well for design because designers rarely edit the exact same property simultaneously, and when they do, either value is acceptable (no meaningful merge of two colors). Cursor positions and selections are broadcast via WebSocket to all editors as ephemeral state. Each editor maintains a WebSocket connection to the collaboration server. Operations are sent immediately on change and broadcast to all other editors. Latency target: under 100ms from edit to visibility on other screens.”}},{“@type”:”Question”,”name”:”How does Figma render complex vector graphics in the browser?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Figma uses WebGL (GPU-accelerated 2D rendering) with a custom rendering engine compiled to WebAssembly. Why not SVG: each element is a DOM node — 10,000+ elements make the DOM too slow. Why not Canvas 2D: CPU-rendered, too slow for complex effects (blurs, shadows). WebGL + Wasm runs at near-native speed on the GPU. The pipeline: traverse the document tree, convert visible nodes to GPU draw commands, batch for minimal draw calls. Optimizations: viewport culling (only render visible elements), level-of-detail (simplify small elements when zoomed out), and incremental rendering (on a property change, re-render only the affected element and overlapping elements — cache the rest as textures). This handles 100,000+ elements at smooth 60fps.”}}]}