Explain Flutter's 3-tree rendering architecture: Widget, Element, and RenderObject
TL;DR: Flutter maintains three parallel trees: Widgets (immutable descriptions), Elements (mutable nodes that reconcile widget diffs and hold State), and RenderObjects (layout and paint nodes). This separation enables efficient rebuilds.
Full Answer
Widget Tree
Widgets are immutable configuration objects. Every call to build() creates a new widget object. They're cheap to create and describe what the UI should look like.
Element Tree
Elements are the mutable nodes that hold the live state. When a widget is built for the first time, Flutter creates a corresponding Element. On rebuild, Flutter walks the element tree and matches new widgets to existing elements (reconciliation). If the runtimeType and key match, the element is updated with the new widget. Otherwise, a new element (and subtree) is created.
RenderObject Tree
RenderObjects handle layout (sizes, positions) and painting (canvas commands). Not every element has a RenderObject — only those that render something. RenderObjects are expensive to create, so Flutter keeps them alive across rebuilds.
This is why const constructors matter: a const widget with unchanged props doesn't rebuild its subtree at all — Flutter's element reconciliation skips it entirely.
Interview Tip
Key insight for interviews: Widgets are cheap (recreated every build), Elements are moderately expensive (created once, updated), RenderObjects are expensive (created once, kept alive). The separation lets Flutter be both fast and flexible.