Figma, 2016–2026  / field guide
Practitioner field guide · 2026-10-17 · Distributed systems

Rent the store, own the layer in front of it: ten years of Figma

Between 2016 and 2026 Figma went from one Postgres instance and a TypeScript sync server to a company with a $545 million, five-year AWS commitment, and in that decade it did not publish a single migration off a managed datastore. What it built instead, again and again, was a thin layer it owns in front of a store it rents. This guide reconstructs those layers from Figma's own postmortems and design posts and from upstream git history, and gives an architect the rule for when that move works and when it only postpones a migration.

38 distinct sources (46 ledger rows) 8 Figma subsystems traced 3 postmortems + 2 design breaks Evidence through October 2026 Read: 28 min
01

The territory

One company, one decade, one recurring move. Why Figma, and why now: its 2025 S-1 put an audited number on the infrastructure bill for the first time, and in the first half of 2026 it published the last two layers of the pattern (a Redis proxy and a Postgres pooler), which closes the arc that began with DBProxy in 2023.

$545M
Minimum AWS spend committed over five years, signed 2025-05-31
9 mo
To horizontally shard RDS Postgres behind DBProxy rather than migrate stores
100%
Engine CPU on one ElastiCache node: four disruptions over June 6 and 7
95%
Of edits durably saved within 600 ms after the journal shipped

The engineering problem, stated without the company: how do you keep a growing real-time product on storage you did not build, when the storage is about to stop being enough? The two textbook answers are to scale up the store you have until it breaks, or to migrate to a store designed for the scale you expect. Figma's record shows a third answer used five times: leave the store where it is, and insert a layer you own that encodes something only your application knows (a shard key, a document boundary, a priority, an invalidation rule).

The surprise. Every system Figma has described building in-house since 2018 is that kind of layer, not a store. DBProxy sits in front of RDS Postgres. LiveGraph sits on the Postgres replication stream. FigCache sits in front of ElastiCache. PGKeeper replaced PgBouncer in front of Postgres. The multiplayer server sits in front of S3 checkpoints and a DynamoDB journal. The one thing Figma built at the substrate level, its own programming language Skew, is the one thing it published deleting. This is an inference from what Figma chose to publish; an unpublished in-house store would break it, and none is described in the 38 sources here.

Figure 1 · Each rented primitive gained an owned layer, none was replaced

Owned by Figma

Rented from AWS

RDS Postgres

Replication stream

ElastiCache Redis

S3 and DynamoDB

ECS, then EKS

DBProxy 2023-24
PGKeeper 2026

LiveGraph 2021
rebuilt after sharding

FigCache 2025-26

Multiplayer journal 2022

Platform abstraction
kept across the move

Owned by Figma

Rented from AWS

RDS Postgres

Replication stream

ElastiCache Redis

S3 and DynamoDB

ECS, then EKS

DBProxy 2023-24
PGKeeper 2026

LiveGraph 2021
rebuilt after sharding

FigCache 2025-26

Multiplayer journal 2022

Platform abstraction
kept across the move

Five rented primitives, five owned layers; the arrows point from what Figma wrote to what it rents. The only substrate it owned outright, the Skew language, it deleted in 2024. Years are when each layer shipped or was first described. Sources: Figma 2018, 2024, 2026.
Diagram source

Scope. Covered: the collaboration server, the metadata database, the real-time query layer, the cache plane, connection pooling, compute orchestration, and the client engine where it explains a server decision. Not covered: AI features and the MCP server, Dev Mode and FigJam product logic, the data warehouse beyond its ingestion path, security programs beyond plugin sandboxing, and organisation or hiring. Evidence limit: direct page fetches were blocked in this session; Figma's posts were read through search-retrieved excerpts, and upstream repositories were read first-hand through git. The ledger marks which is which.

02

How it is actually built

Figma in 2026 as two planes: a document plane where one process is the authority for one file, and a metadata plane where every rented store has an owned layer in front of it.

Figure 2 · Owned layers (bold) over rented stores (cylinders)

Metadata plane

Document plane

Browser and desktop client

edits over WebSocket

replication stream

live query results

C++ engine in WebAssembly
WebGPU renderer

Multiplayer, Rust
one authority per file
QueryGraph

Web API

DBProxy
parse and route by shard key

PGKeeper
priority admission

FigCache
RESP proxy

LiveGraph
invalidation cache

S3 checkpoints

DynamoDB journal

RDS Postgres shards

ElastiCache Redis

Kafka change stream

Metadata plane

Document plane

Browser and desktop client

edits over WebSocket

replication stream

live query results

C++ engine in WebAssembly
WebGPU renderer

Multiplayer, Rust
one authority per file
QueryGraph

Web API

DBProxy
parse and route by shard key

PGKeeper
priority admission

FigCache
RESP proxy

LiveGraph
invalidation cache

S3 checkpoints

DynamoDB journal

RDS Postgres shards

ElastiCache Redis

Kafka change stream

The application never talks to a rented store directly on the hot path; each arrow into AWS passes through something Figma wrote. The PGKeeper position below DBProxy is inferred from the two posts, which do not draw them together. Sources: DBProxy, PGKeeper, FigCache, journal.
Diagram source

The document plane is the original design and has barely changed shape. Figma's 2018 Rust post reports that "each document lives exclusively on one specific worker", and the 2019 multiplayer post explains why that matters: the server is the central authority, which let Figma drop the machinery CRDTs carry for the no-authority case and resolve conflicts with last-writer-wins per property per object. What changed underneath is durability. Until 2022 a file's state reached storage only through checkpoints, written every 30 to 60 seconds to S3. The 2022 reliability post adds a journal: each accepted change gets a per-file sequence number and is written asynchronously to a durable store (Figma's own announcement tags DynamoDB), and recovery replays the journal past the last checkpoint. The authority stayed in one process; the window of loss shrank from up to a minute to under a second for 95% of edits.

The metadata plane is where the pattern is clearest. Permissions, files, teams and comments live in Postgres on RDS. In 2020 that was one large instance. Figma first scaled it up and added replicas and PgBouncer, then split it by table (vertical partitioning, 2022-2023), then by row (horizontal sharding, first table live in 2023, published 2024). The shape of each step is the same: a routing layer that knows Figma's data model gets inserted between the application and an unchanged managed engine. In 2024 that layer was DBProxy, which parses SQL, finds the shard key and routes. In 2026 it gained a second owned component, PGKeeper, which replaced PgBouncer because the pooler needed to know which traffic mattered more.

Multiplayer (Rust)

One process is the authority for one file. Rust was chosen in 2018 because the TypeScript server's garbage collector stalled every file on a worker and a Node process per file cost too much memory. Since 2023-24 its QueryGraph sends a client only the page it opened plus that page's read dependencies.

Sources: 2018, 2024

DBProxy

A query proxy between the application and the pooler. It parses each query, routes it by shard key within a "colo" (tables that share a key and layout), and handles load shedding and topology. Logical sharding through Postgres views shipped before any physical move, so the routing could be proven before data moved.

Sources: Figma, pganalyze

LiveGraph

Turns a query into a subscription by reading the Postgres replication stream through Kafka instead of polling. Built when Figma had 500,000 weekly active users and one Postgres; rebuilt after sharding as an invalidation-based cache sharded by query hash.

Sources: 2021, rebuild, @Scale

FigCache

A stateless proxy speaking the Redis protocol in front of ElastiCache, built on Figma's own Go RPC framework over RESP. It decouples Redis connection counts from client fleet size and adds routing, draining, locking and observability in one place.

Sources: Figma, InfoQ

PGKeeper

A Go service exposing gRPC that replaced PgBouncer: pool warming, rate-limited connection churn, a priority semaphore using CoDel, then weighted fair sharing. PGCat was evaluated first. Rolled out with automatic fallback to PgBouncer.

Sources: Figma, Postgres Weekly

Compute and client

Services moved from ECS to EKS in under twelve months (2024), kept behind the same developer-facing abstraction. On the client, the C++ engine went asm.js to WebAssembly (2017) and WebGL to WebGPU (2025) while keeping a WebGL path.

Sources: EKS, WebGPU

03

The decisions that matter

Six forks Figma documented, what it rejected, and the condition under which the rejected option would have been right.

Decision: should collaborative edits converge by algorithm or by authority?

Chosen
  • A central server per file orders edits; last-writer-wins per property per object (2016-2019).
  • Figma: "Since Figma isn't a text editor, we didn't need the power of OTs."
Rejected
  • Operational transformation: more power than a property-based scene graph needs.
  • A true CRDT: its overhead exists to converge without an authority, and Figma has one.
Flips when
  • Edits must merge without the server (offline-first, peer-to-peer), or the data is text where intent preservation matters more than per-field overwrite.

Decision: when the single Postgres runs out, migrate the store or shard it in place?

Chosen
  • Vertical partitioning by table (2022-2023), then horizontal sharding of the same RDS Postgres behind DBProxy (late 2022 to 2024, nine months to the first sharded table).
Rejected
  • CockroachDB, TiDB, Spanner, Vitess and NoSQL stores. Stated reason: a small team should not re-implement a generic sharded database, and Figma's narrower needs called for less.
Flips when
  • Cross-shard transactions or multi-region writes become product requirements, or the routing layer starts reimplementing what a distributed SQL engine already ships. Neither condition is reported for Figma as of 2026 (inferred from what is not published).

Decision: own a connection pooler, or wait for the open-source one?

Chosen
  • PGKeeper (published 2026): priority-aware admission and fair sharing, gRPC to clients.
Rejected
  • PgBouncer: single-threaded, no way to rank critical traffic above misbehaving traffic.
  • PGCat: evaluated and passed over (reason not in the retrieved excerpt).
Flips when
  • Your traffic has one priority class. Upstream's answer to core count is several processes with so_reuseport and peering (merged 2023-2024); a multithread mode is an unmerged PR as of October 2026.

The fourth and fifth decisions are the same shape on different stores. For Redis, Figma kept ElastiCache but stopped letting every service connect to it directly. The FigCache post states the reason plainly: Redis had moved from a non-critical component to the critical path, clusters were nearing connection limits, and applications connected "with various permutations of Redis Cluster-awareness, TLS in-transit encryption, and other connection parameters". A proxy fixes the last point by making one client the only client. For compute, Figma left ECS for EKS because ECS had no StatefulSets (its etcd workaround was "fragile and hard to maintain") and could not run Helm-packaged software; it scoped the move to the core and kept the abstraction service owners saw, which is why it took under a year.

The sixth runs the other way. Skew, a compile-to-JavaScript language Figma's co-founder wrote in 2015, was the one substrate-level system Figma owned. WebAssembly removed its performance case, and its cost (hiring, tooling, integration) stayed. Figma retired it with a Skew-to-TypeScript transpiler so teams kept shipping during the move. The public repository agrees: 858 commits, last code change 2021-03-04, a README edit in February 2024 and nothing since.

Figure 3 · The rule Figma's record implies, as a decision tree

no

yes

no

yes

no

yes

Is the store's engine
the binding limit?
CPU, IOPS, single table size

Does the fix need knowledge
only your app has?
shard key, priority, invalidation

Can a small team
migrate every query?

Add an owned layer
in front of the store

Use the vendor feature
or upstream release

Build the routing layer,
then split the store under it

Migrate to a store
built for the scale

no

yes

no

yes

no

yes

Is the store's engine
the binding limit?
CPU, IOPS, single table size

Does the fix need knowledge
only your app has?
shard key, priority, invalidation

Can a small team
migrate every query?

Add an owned layer
in front of the store

Use the vendor feature
or upstream release

Build the routing layer,
then split the store under it

Migrate to a store
built for the scale

A layer is the right move only while the store's engine limit is not the binding constraint; when it is, the layer's job is to make the split possible, not to avoid it. Reconstructed from the 2020 postmortem and the 2023 and 2024 database posts.
Diagram source
DecisionChosenRejectedBecauseFlips whenEvidence
Edit convergenceServer authority, LWW per propertyOT; true CRDTNot a text editor; a central authority existsOffline or peer merge requiredFigma 2019
Sync server runtimeRust, process per fileTypeScript on NodeGC stalls a whole worker; per-file Node too heavyPer-file state small, GC pauses below edit latency budgetFigma 2018
Metadata scale-outShard RDS Postgres via DBProxyCockroachDB, TiDB, Spanner, Vitess, NoSQLSmall team; narrower needs; no store migrationCross-shard transactions become coreFigma 2024
Real-time queriesReplication-stream driven; later invalidation cachePolling; incremental view maintenancePolling multiplies DB load; IVM hard to scaleFew subscribers per query, relaxed freshnessFigma 2021
Cache accessFigCache proxyDirect client librariesConnection limits; inconsistent client configsFew services, one client libraryFigma 2026
Connection poolingPGKeeperPgBouncer; PGCatSingle thread; no priority classesSingle priority classFigma 2026
In-house languageCompile Skew away to TypeScriptKeep maintaining SkewPerformance case gone after Wasm; hiring and tooling costThe language still buys something nothing else doesFigma 2024
04

What broke in production

Three published incidents and two published design breaks, in two classes: one workload saturating a shared rented store, and a new topology silently invalidating an assumption the layer above it made.

Class A · One workload saturates a shared store

Both of Figma's formal outage postmortems are this class, and both landed on a managed service whose limit Figma could not change from inside. The layers that followed (partitioning, DBProxy, FigCache, PGKeeper) are each a way of making one workload unable to spend everyone's budget.

Postmortem

One query, one database, everyone down (January 2020)

AssumptionThe single large RDS instance had headroom for any query the application issued.
What happenedDay 1: a long-running expensive query drove database CPU up until it was found and cancelled at 6:54 AM PST. Day 2: a different profile, with write IOPS and lock contention high and CPU low. Cancelling queries and raising IOPS helped only briefly.
Blast radiusTwo consecutive days of site degradation; every product surface shared the one database.
FixRestart to disable a background process suspected of adding write load, then an emergency engine upgrade already tested in staging; tighter limits on query running time. The structural fix was the 2022-2024 partitioning work.
Design ruleOn a single shared database, query runtime limits are an availability control, not a hygiene setting. Set them before the first incident, per caller.
Postmortem

Pub/sub on a cluster-mode cache node (June 2022)

AssumptionA cluster-mode-enabled ElastiCache deployment spreads load across shards.
What happenedHigh publish/subscribe load drove one node's Engine CPU to 100%. In classic Redis Cluster pub/sub every message propagates to every node, so sharding the keyspace did not shard the messages. A failover ran slower than expected.
Blast radiusFour disruptions over roughly a day. Open files kept working; opening files and collaborating failed. No data loss.
FixTraffic moved to new ElastiCache clusters. Figma's 2026 FigCache post cites this incident as motivation for putting a proxy in front of every Redis cluster.
Design ruleKnow which operations your store fans out to every node regardless of partitioning; those set the cluster's ceiling, not the shard count.

Figure 4 · Why a sharded cache had a single hot node

Clients opening filesCache node 3Cache node 2Cache node 1Publisher serviceClients opening filesCache node 3Cache node 2Cache node 1Publisher serviceEngine CPUreaches 100%Loaded files keep working.New opens and collaboration fail.PUBLISH, high volumeforward every messageforward every messageopen file, join sessionno response
Clients opening filesCache node 3Cache node 2Cache node 1Publisher serviceClients opening filesCache node 3Cache node 2Cache node 1Publisher serviceEngine CPUreaches 100%Loaded files keep working.New opens and collaboration fail.PUBLISH, high volumeforward every messageforward every messageopen file, join sessionno response
Classic cluster pub/sub fans every message to every node over the cluster bus, so publish volume costs the same on every shard. Sharded pub/sub, which confines a message to its slot's shard, merged upstream in January 2022 and first tagged in Redis 7.0; whether Figma's managed engine version offered it in June 2022 is not stated (open). Sources: Figma, Redis docs, redis#8621.
Diagram source

Class B · The new topology breaks an assumption the layer above made

This class has no outage postmortem in the record, which is itself informative: Figma caught both cases before they became incidents, or did not publish them. Both are a layer that was correct against the old shape of the store and wrong against the new one.

Figure 5 · What partitioning did to LiveGraph's input

stopgap: merge all streams into one

2024 onward: partitioned

invalidate by query hash

Partition A

Invalidator
only topology-aware part

Partition B

Query cache
refetch on miss

2021: one database

one ordered stream

Postgres

LiveGraph
applies updates in order

stopgap: merge all streams into one

2024 onward: partitioned

invalidate by query hash

Partition A

Invalidator
only topology-aware part

Partition B

Query cache
refetch on miss

2021: one database

one ordered stream

Postgres

LiveGraph
applies updates in order

One database gave one ordered stream; partitioning gave several with no order between them. The stopgap restored one stream and with it one bottleneck; the rebuild stopped needing an order at all. Source: Figma, LiveGraph rebuild.
Diagram source
Design break

Partitioning removed LiveGraph's global order

AssumptionOne database produces one totally ordered stream of updates.
What happenedVertical partitioning produced several replication streams with no global order between them. LiveGraph's design had relied on that order.
Blast radiusNo outage reported; the stated cost was a stopgap and a rebuild.
FixStopgap: merge all streams into one, restoring the assumption at the price of a single ingest bottleneck. Rebuild: an invalidation-based cache sharded by query hash, with an invalidator as the only component aware of database topology.
Design ruleBefore splitting a store, list every consumer of its change stream and what ordering each assumes. Invalidate-and-refetch survives a topology change that incremental maintenance does not.
Postmortem

The borrowed sandbox had escapes (2019)

AssumptionAn in-process JavaScript sandbox library (the Realms shim) contains untrusted plugin code.
What happenedSeveral independent sandbox-escape vulnerabilities were found in the shim; upstream fixed four security-critical bugs on 2019-10-02, one rated critical.
Blast radiusNo evidence of exploitation after an audit of all published plugins. Plugin publishing and updates were halted.
Fix"A fundamental change to our technology stack to prevent this class of bug." The excerpt does not name the replacement; community posts say an interpreter compiled to WebAssembly (unverified).
Design ruleWhen the isolation boundary is a library inside your process, plan a kill switch on distribution (here, publishing) before you need it.

A fifth, smaller entry belongs on the durability path. During the 2018 Rust rewrite, Figma tried two compression libraries from Mozilla's Servo project; both had defects that caused document data loss, and Figma fell back to a mature C library. The rule generalises: a rewrite for performance should not also swap the dependencies on the write path to storage. Change one side of the durability boundary at a time.

05

Numbers you can plan against

Figma publishes few absolute scale figures. Most of what exists is a ratio, a duration or a commitment, and two headline reliability figures are Figma's own claims.

MetricValueContextKindAs ofSource
Client load time after asm.js to Wasm3× fasterInit, download and first render combinedMeasured by Figma2017Figma
Wasm parse speed vs asm.js~20×Same engine binaryMeasured by Figma2017Figma
Peak CPU on the single metadata DB65%+One large RDS PostgresMeasured2020Figma
Cost of each vertical move~30 s, ~2% requestsPartial availability per table-group cutoverMeasured2022-23Figma
Time to first horizontally sharded table9 monthsSmall databases team, existing RDSReported2023-24Figma
Users when LiveGraph was first built500,000 WAUOne Postgres instanceReportedc. 2020@Scale
Checkpoint interval before the journal30-60 sWhole file, compressed, to S3Reported2022Figma
Edits durably saved95% within 600 msAfter journal rolloutMeasured by Figma2022Figma
Slowest file loads33% fasterDynamic page loading via QueryGraphMeasured by Figma2024Figma
ECS to EKS migration<12 monthsCore platform, abstraction keptReported2024Figma
AWS minimum commitment$545M / 5 yrRenewal signed 2025-05-31Audited filing2025S-1
Commitment as share of revenue~$109M/yr, ~12%Against $821M trailing revenueDerived by a third party2025Duckbill
Cache-layer uptimesix ninesSince FigCache for the main API, 2H 2025Claimed by Figma2026Figma
PGKeeper load test3× peak QPSBefore rollout; database SLO above 99.99% sinceClaimed (SLO via summary)2026Figma
Skew repository858 commitsLast code change 2021-03-04Counted from git2026-10evanw/skew

What to plan against. The figure that transfers is the cost of a cutover through an owned layer: about 30 seconds and 2% of requests per vertical move in 2022-2023, falling to the seconds range for the horizontal moves once DBProxy owned routing (secondary sources report about 10 seconds of partial primary availability for the first sharded table; Figma's own excerpt was not retrieved, so treat it as unconfirmed). The cost frame is the S-1: roughly $109 million a year of committed AWS spend is the price of not running stores, and every layer in this guide is a few engineers' worth of code next to it. That ratio, not a benchmark, is why the pattern held.

Read these carefully

Figma has not published request rates, shard counts, table sizes or per-store costs. The six nines and 99.99% figures are self-reported and the latter reached this guide through a summary. The $109 million annual figure is a third party's division of the five-year minimum, not a reported spend. No independent measurement exists for any Figma reliability claim here.

◆

The lesson: own the semantics, rent the bytes

Carry this into your own design review

When a managed store starts to fail you, first ask what the failure needs to know. If the fix needs knowledge only your application has (which rows belong together, which caller matters more, which query a change invalidates, which process owns a document), build a thin layer that holds that knowledge and keep the store. If the fix needs a different storage engine, the layer cannot replace that; its job is to make the split cheap. Figma's 2020 database outage was the second kind, and DBProxy made the eventual split nine months of work instead of a store migration.

Three conditions make the rule work, and Figma's record shows each one. The layer has to be the only path to the store, or it encodes nothing: FigCache existed because a dozen client configurations had become a dozen ways to reach Redis. The layer has to stay stateless or nearly so, because state turns it into the store you meant not to build: DBProxy, FigCache and PGKeeper are all described as proxies, and LiveGraph moved from maintaining results to invalidating them. And the layer has to be cheap to roll back: PGKeeper shipped with automatic fallback to PgBouncer, and logical sharding through views proved DBProxy's routing before any row moved.

Where the rule fails: the layer inherits every assumption about the store's topology, and the topology is what you are about to change. LiveGraph is the worked example. Inventory those assumptions before the split, not after.

06

The evidence wall

Every source behind this page, graded. Figma posts were read through retrieved excerpts; source-code entries were read first-hand from git. Filter by kind.

Postmortem Figma2020-01

Postmortem: Service disruption on January 21-22, 2020

Two days, two profiles on one RDS Postgres: an expensive query saturating CPU, then write IOPS and lock contention with low CPU. Fixed by cancelling queries, disabling a background process and an emergency engine upgrade.

Carry forwardA single shared database needs per-caller runtime limits before it needs a bigger instance.
https://www.figma.com/blog/post-mortem-service-disruption-on-january-21-22-2020/
Postmortem Figma2022-06

Postmortem: Service disruptions on June 6 & 7 2022

Pub/sub load drove Engine CPU to 100% on one cluster-mode-enabled ElastiCache node; four disruptions; open files kept working, new opens and collaboration failed; no data loss.

Carry forwardFind the operations your store broadcasts to every node; they cap the cluster regardless of shard count.
https://www.figma.com/blog/postmortem-service-disruptions-on-june-6-and-7-2022/
Postmortem Figma2019-10

An update on plugin security

Sandbox-escape bugs in the Realms shim; plugin publishing and updates halted; audit found no exploitation; a fundamental stack change to remove the bug class.

Carry forwardAn in-process isolation library needs a distribution kill switch designed in advance.
https://www.figma.com/blog/an-update-on-plugin-security/
Source redis/redis2022-01-03

Sharded pubsub implementation (#8621)

Read from git: commit 9f8885760, co-authored by an AWS engineer, first tagged in 7.0-rc1. Confines pub/sub messages to the shard owning the channel slot.

Carry forwardUpstream fixes for a vendor-hosted engine reach you only on the vendor's version schedule.
https://github.com/redis/redis/pull/8621
Source pgbouncer2023-04-20

Add PgBouncer peering support (#666)

Read from git: upstream scaled PgBouncer across cores with multiple processes, so_reuseport and peering for cancel requests (rolling-restart redesign followed in #902, 2024-05).

Carry forwardMulti-process scale-out adds throughput, not priority between traffic classes.
https://github.com/pgbouncer/pgbouncer/pull/666
Source pgbouncer2026-08-27

Multithread mode (#1386, unmerged)

Read from git: 12 commits from 2025-09-28 to 2026-08-27 on a PR head not reachable from master; an earlier attempt (#1244) is also unmerged.

Carry forwardWhen the feature you need is an unmerged PR, building around it is a bet on timing, not on code.
https://github.com/pgbouncer/pgbouncer/pull/1386
Source evanw/skew2024-02-20

Skew language repository

Read from git: first commit 2015-03-15 by Evan Wallace, 858 commits, last code change 2021-03-04, a README edit in 2024.

Carry forwardThe substrate Figma owned outright is the part it retired.
https://github.com/evanw/skew
Source GitHub Advisory DB2019-10

GHSA-7cg8-pq9v-x98q: realms-shim sandbox breakout

Critical advisory: realms-shim versions before 1.2.1 allow escape from the sandbox.

Carry forwardTrack advisories for any library that is your security boundary as if it were your own code.
https://github.com/advisories/GHSA-7cg8-pq9v-x98q
Decision record Figma2019-10

How Figma's multiplayer technology works

Rejects OT ("Figma isn't a text editor") and true CRDTs; server authority with last-writer-wins per property.

Carry forwardIf you have an authority, you can drop the cost CRDTs pay for not having one.
https://www.figma.com/blog/how-figmas-multiplayer-technology-works/
Decision record Figma2024-03-14

How Figma's databases team lived to tell the scale

Evaluates and rejects CockroachDB, TiDB, Spanner, Vitess and NoSQL; shards existing RDS Postgres behind DBProxy with colos and logical sharding first; nine months.

Carry forwardProve routing on logical shards before moving a row.
https://www.figma.com/blog/how-figmas-databases-team-lived-to-tell-the-scale/
Case study Figma2023-04

The growing pains of database architecture

One large RDS instance at 65%+ peak CPU in 2020; vertical partitioning by table group; about 30 seconds and 2% of requests per move.

Carry forwardVertical splits buy time until one table outgrows one machine.
https://www.figma.com/blog/how-figma-scaled-to-multiple-databases/
Eng blog Figma2018-05

Rust in production at Figma

TypeScript sync server rewritten in Rust: GC stalls blocked every file on a worker; a Node process per file cost too much memory; Servo compression crates caused data loss.

Carry forwardChange one side of the durability boundary at a time.
https://www.figma.com/blog/rust-in-production-at-figma/
Eng blog Figma2019-08

How to build a plugin system on the web and also sleep well at night

Iframe sandbox tried first, plugins reach the app only through whitelisted messages; the in-process option chosen later failed in 2019.

Carry forwardWrite down the sandbox you rejected; you may need it back.
https://www.figma.com/blog/how-we-built-the-figma-plugin-system/
Eng blog Figman.d.

Keeping it 100(x) with real-time data at scale

Partitioning broke LiveGraph's global ordering; stopgap merged streams; rebuilt as an invalidation cache sharded by query hash.

Carry forwardInvalidate-and-refetch survives topology changes that incremental maintenance does not.
https://www.figma.com/blog/livegraph-real-time-data-at-scale/
Eng blog Figma2022-10

Making multiplayer more reliable

Checkpoints every 30-60 s to S3 plus a per-file journal with sequence numbers; 95% of edits saved within 600 ms.

Carry forwardSize the durability window explicitly; it is a product number.
https://www.figma.com/blog/making-multiplayer-more-reliable/
Eng blog Figma2024-08-08

How we migrated onto K8s in less than 12 months

ECS to EKS: no StatefulSets, a fragile etcd wrapper, no Helm; scope held to the core with the service-owner abstraction unchanged.

Carry forwardKeep the abstraction your users see fixed while you swap the orchestrator.
https://www.figma.com/blog/migrating-onto-kubernetes/
Eng blog Figma2025-10

Figma rendering: powered by WebGPU

Renderer moved WebGL to WebGPU for compute shaders and fewer global-state bugs, keeping a WebGL path during rollout.

Carry forwardKeep the old backend live while the new one earns trust.
https://www.figma.com/blog/figma-rendering-powered-by-webgpu/
Eng blog Figman.d.

Figma's data pipeline upgrade

Daily syncs taking hours or days replaced by in-house CDC to Kafka, one topic per table, into Snowflake.

Carry forwardThe same change stream feeds both real-time product and analytics.
https://www.figma.com/blog/figmas-data-pipeline-upgrade/
Eng blog InfoQ2026-05-05

Figma builds in-house Redis proxy to hit six nines uptime

FigCache built on ResPC, Figma's Go RPC framework over RESP; in production since 2H 2025.

Carry forwardDates the FigCache post; the uptime figure is still Figma's claim.
https://www.infoq.com/news/2026/05/figma-redis-figcache/
Eng blog Jamsocketn.d.

You might not need a CRDT

Quotes Wallace: with the server as central authority, Figma removes CRDT overhead for a faster, leaner implementation.

Carry forwardCorroborates the multiplayer post's rejection of true CRDTs.
https://jamsocket.xyz/blog/you-might-not-need-a-crdt
Eng blog Agoric2019-10-02

Realms-shim security updates

Upstream maintainer: four security-critical bugs fixed in realms-shim 1.2.0 and SES 0.6.3.

Carry forwardDates and sizes the 2019 plugin incident from the library side.
https://agoric.com/realms-shim-security-updates/
Eng blog Postgres Weekly2026-05-06

Issue #647

Dates PGKeeper and records that PGCat was evaluated first; Go and PGX.

Carry forwardThe bound on PGKeeper's publication date.
https://postgresweekly.com/issues/647
Talk Postgres FM2024

Episode 100: To 100TB, and beyond!

Figma's databases tech lead with Notion and Adyen on very large Postgres. Guest list only retrieved; no timestamped claim cited.

Carry forwardWhere to hear the sharding trade-offs argued across three companies.
https://postgres.fm/episodes/to-100tb-and-beyond
Paper INRIA2011

Conflict-free replicated data types (Shapiro et al.)

Defines CRDTs: convergence without coordination. Read beside Figma 2019 to see which guarantees a central authority makes redundant.

Carry forwardCRDT cost buys coordinator-freedom; do not pay for it if you have a coordinator.
https://hal.sorbonne-universite.fr/inria-00609399v1
Vendor Redisn.d.

Redis Pub/Sub documentation

Classic cluster pub/sub propagates each message to every node; sharded pub/sub confines it to one shard.

Carry forwardThe mechanism behind the 2022 incident, in the vendor's words.
https://redis.io/docs/latest/develop/pubsub/
07

Build a miniature, then productionise it

Six rungs that reproduce Figma's layers on a laptop, crossing from toy to production-shaped at rung four.

One authority per document

A WebSocket server that pins each document id to one worker process and applies last-writer-wins per (object, property). Two browser tabs editing the same rectangle.

Done when: concurrent edits to different properties both survive, and to the same property the later server-ordered one wins.  Teaches: what a central authority removes from the CRDT problem.

Checkpoint, then journal

Write a full snapshot every 30 seconds; kill the process mid-edit and count lost edits. Add an append-only journal with per-document sequence numbers and replay on start.

Done when: a kill -9 loses no acknowledged edit and recovery replays only entries after the snapshot's sequence number.  Teaches: the durability window as a design parameter.

A routing proxy over two Postgres instances

A proxy that parses SQL (use a Postgres parser library), extracts a shard key from the WHERE clause and routes; reject queries without one. Start with both "shards" as views on one database.

Done when: the application's test suite passes against logical shards before any row moves.  Teaches: logical before physical sharding.

Break the change-stream consumer

Build a subscription service on one database's logical replication stream, then split a table to a second database. Watch ordering-dependent results go wrong; rebuild it as invalidate-and-refetch.

Done when: subscriptions stay correct across the split with no global stream.  Teaches: the LiveGraph failure, first-hand.

Reproduce the pub/sub ceiling

A three-node Redis Cluster; drive PUBLISH from one client and measure CPU on every node. Repeat with SPUBLISH.

Done when: you have a graph showing classic pub/sub cost on every node and sharded pub/sub on one.  Teaches: which operations ignore your partitioning.

Priority admission in front of the pool

Put a pooler in front of Postgres with two traffic classes and a CoDel-style queue: drop low-priority requests whose queue wait exceeds a target. Inject a misbehaving batch client.

Done when: interactive p99 stays flat while the batch client saturates, and an automatic fallback to plain PgBouncer works under load.  Teaches: why PGKeeper exists and why it shipped with a way back.

08

Keep hunting

The queries that found this material. Figma's titles are playful, so search the internal nouns (DBProxy, LiveGraph, QueryGraph, FigCache, PGKeeper) rather than the problem.

Postmortems and incidents

  • site:figma.com/blog postmortem service disruption
  • "Engine CPU" "Cluster-Mode Enabled" ElastiCache publish subscribe
  • Figma "update on plugin security" Realms shim

Decision records in blog form

  • Figma DBProxy colos "logical sharding" CockroachDB Vitess
  • Figma LiveGraph "globally ordered" invalidation cache
  • Figma PGKeeper PgBouncer PGCat CoDel

Upstream code that explains the incident

  • git log --grep='sharded pub' redis/redis
  • git fetch origin '+refs/pull/*/head:refs/remotes/pr/*' # then merge-base --is-ancestor

Cost and scale

  • Figma S-1 "cloud hosting" commitment minimum
  • Figma "single Postgres" "weekly active users" LiveGraph
09

References

  1. Figma, Postmortem: Service disruption on January 21-22, 2020 Postmortem, 2020-01. Indexed 2026-10-17.
  2. Figma, Postmortem: Service disruptions on June 6 & 7 2022 Postmortem, 2022-06. Indexed 2026-10-17.
  3. Figma, An update on plugin security Postmortem, 2019-10. Indexed 2026-10-17.
  4. redis/redis, Sharded pubsub implementation (#8621) Source, 2022-01-03. Indexed 2026-10-17.
  5. pgbouncer, Add PgBouncer peering support (#666) Source, 2023-04-20. Indexed 2026-10-17.
  6. pgbouncer, Multithread mode (#1386, unmerged) Source, 2026-08-27. Indexed 2026-10-17.
  7. evanw/skew, Skew language repository Source, 2024-02-20. Indexed 2026-10-17.
  8. GitHub Advisory DB, GHSA-7cg8-pq9v-x98q: realms-shim sandbox breakout Source, 2019-10. Indexed 2026-10-17.
  9. Figma, How Figma's multiplayer technology works Decision record, 2019-10. Indexed 2026-10-17.
  10. Figma, How Figma's databases team lived to tell the scale Decision record, 2024-03-14. Indexed 2026-10-17.
  11. Figma, The growing pains of database architecture Case study, 2023-04. Indexed 2026-10-17.
  12. Figma, Inc., Form S-1 Case study, 2025-07. Indexed 2026-10-17.
  13. Figma, WebAssembly cut Figma's load time by 3x Eng blog, 2017-06. Indexed 2026-10-17.
  14. Figma, Rust in production at Figma Eng blog, 2018-05. Indexed 2026-10-17.
  15. Figma, How to build a plugin system on the web and also sleep well at night Eng blog, 2019-08. Indexed 2026-10-17.
  16. Figma, LiveGraph: real-time data fetching at Figma Eng blog, 2021-10. Indexed 2026-10-17.
  17. Figma, Keeping it 100(x) with real-time data at scale Eng blog, n.d.. Indexed 2026-10-17.
  18. Figma, Making multiplayer more reliable Eng blog, 2022-10. Indexed 2026-10-17.
  19. Figma, How we migrated onto K8s in less than 12 months Eng blog, 2024-08-08. Indexed 2026-10-17.
  20. Figma, Compiling away our custom programming language Eng blog, 2024-05. Indexed 2026-10-17.
  21. Figma, Speeding up file load times, one page at a time Eng blog, 2024. Indexed 2026-10-17.
  22. Figma, Figma rendering: powered by WebGPU Eng blog, 2025-10. Indexed 2026-10-17.
  23. Figma, Figma's data pipeline upgrade Eng blog, n.d.. Indexed 2026-10-17.
  24. Figma, Figma's next-generation data caching platform Eng blog, 2026. Indexed 2026-10-17.
  25. Figma, PGKeeper: building the bouncer we needed for Postgres Eng blog, 2026. Indexed 2026-10-17.
  26. pganalyze, How Figma built DBProxy for sharding Postgres Eng blog, 2024-03. Indexed 2026-10-17.
  27. InfoQ, Figma builds in-house Redis proxy to hit six nines uptime Eng blog, 2026-05-05. Indexed 2026-10-17.
  28. InfoQ, Figma moves from ECS to Kubernetes Eng blog, 2024-09. Indexed 2026-10-17.
  29. Duckbill, Figma's $300k daily AWS bill isn't the scandal you think it is Eng blog, 2025-07. Indexed 2026-10-17.
  30. Jamsocket, You might not need a CRDT Eng blog, n.d.. Indexed 2026-10-17.
  31. Agoric, Realms-shim security updates Eng blog, 2019-10-02. Indexed 2026-10-17.
  32. Simon Willison, Figma's journey to TypeScript (link note) Eng blog, 2024-05-04. Indexed 2026-10-17.
  33. Postgres Weekly, Issue #647 Eng blog, 2026-05-06. Indexed 2026-10-17.
  34. @Scale, LiveGraph: scaling real-time data access Talk, n.d.. Indexed 2026-10-17.
  35. Postgres FM, Episode 100: To 100TB, and beyond! Talk, 2024. Indexed 2026-10-17.
  36. INRIA, Conflict-free replicated data types (Shapiro et al.) Paper, 2011. Indexed 2026-10-17.
  37. ACM Queue, Controlling Queue Delay (Nichols, Jacobson) Paper, 2012-05. Indexed 2026-10-17.
  38. Redis, Redis Pub/Sub documentation Vendor, n.d.. Indexed 2026-10-17.