Skip to content

CONCEPT Cited by 1 source

Derived subtree

A derived subtree is a subtree of a document tree whose structure and property values are not authored directly but computed from other sources of truth — and kept in sync with those sources via a reactive framework. The authored artifact is a blueprint describing how the subtree should be derived; the framework materializes it, tracks what inputs it read, and re-materializes the affected parts when any of those inputs change.

Canonical source: sources/2026-04-21-figma-rebuilt-foundations-of-component-instances — Figma's Materializer reframes component-instance maintenance (a decade-old bespoke runtime) plus new features like rich-text-from-CMS nodes as instances of the same abstraction.

Shape

A derived-subtree system has three pieces:

  1. Source of truth — the authoring input: a main component, a rich-text block list, a CMS document, a schema definition. Owned by the user / product / external system.
  2. Blueprint — feature-owned code that reads the source of truth and describes what subtree should exist: what nodes, what properties, what children, what overrides. Not a one-shot template — a function the framework runs whenever inputs change.
  3. Derived subtree — the materialized output nodes, living in the same document tree as hand-authored nodes. Participates in layout, rendering, selection, every other system that operates on the tree. Its existence and values are owned by the framework; user edits that fall within the derived region are either treated as overrides (per blueprint) or rejected.

The framework owns the reactive machinery: dep tracking, invalidation, re-materialization. The feature owns only the blueprint. This is the load-bearing separation of concerns.

Figma's two instances

Component instances. Blueprint describes how an instance resolves itself from its main component: which properties inherit, which overrides apply, which children exist. Before Materializer, this logic lived in Instance Updater, a bespoke 2016-era runtime that also accreted auto-layout and variable-evaluation responsibilities. After Materializer, instance resolution is one blueprint and nothing else — layout lives in layout systems, variables live in variable systems.

Rich text nodes. Blueprint uses rich-text blocks (<h1>, <p>, <img>) as the input that tells Materializer to create corresponding text or image nodes. Content stored in an external CMS; rich text was the first net-new feature built on Materializer.

A third, slots (open beta April 2026), composes on top of Materializer rather than introducing its own bespoke reactivity.

Why the abstraction is load-bearing

Derived state is common enough that every sizable client runtime grows it organically. The failure mode Figma describes is accreting a per-feature reactive substrate: Instance Updater, originally simple, grew "specialized, bespoke logic" for each wave of new features (auto layout 2019 → variants 2020 → component properties 2022 → variables 2023). Two consequences named in the post:

  • Coarse invalidation. "The old system updated entire instances whenever anything changed." Even unrelated edits triggered recursive cascades through deeply nested component trees.
  • System fighting. "Different systems would 'fight' over the same subtree, repeatedly invalidating each other." Each subsystem's internal reactivity assumed authority; they collided on shared state.

Factoring derivedness into an abstraction has the same feature-velocity compound effect as the object-tree model did for schema: new dynamic-content features ship on the framework instead of paying to rebuild reactivity. Rich text + slots in April 2026 are the proof points.

Sibling patterns in other systems

  • React — components are functions from props+state to a virtual DOM subtree; React reconciles the real DOM. React's invalidation is pull-based (check-on-read).
  • CSS variables + custom properties — computed style is a derived subtree of the render tree, re-derived on variable changes.
  • Database materialized views — stored query results kept in sync with base tables via incremental view maintenance; same "blueprint over source → derived state" shape at the storage layer.
  • Reactive frameworks (MobX, SolidJS, Vue refs) — observed-read dependency tracking + push notifications on source writes, applied to application state rather than a document tree.

Materializer applies the pattern at document-tree granularity with Figma's specific workload constraint (cross-tree references, deeply nested components) driving the push-based choice.

Cost surfaces

  • Dependency cache memory. Tracking what each derived node read during materialization requires per-read bookkeeping. Figma names "additional dependency caches" as a cost, with file load time and memory usage as potentially-affected metrics.
  • Blueprint correctness. Bugs in a blueprint present as silent divergence from intended output — the same failure-mode class as a stale read dep in concepts/write-dependency-graph. Figma gated Materializer rollout on side-by-side validation against hundreds of thousands of real files for months.
  • Framework expressiveness ceiling. The abstraction only pays off when the new feature fits — rich text and slots did, but novel feature classes may need framework extension rather than just a new blueprint.

Seen in

Last updated · 200 distilled / 1,178 read