Sparround

Widget tree: Stateless and Stateful

In Flutter everything is a widget: a button, a padding, an entire screen. Widgets form a tree, and each one is an immutable configuration — the widget object itself never changes; a new one is created instead.

There are two core kinds:

  • StatelessWidget — has no internal state; the same input always produces the same output
  • StatefulWidget — has changing state, which lives in a separate State object

The reason for that split: the widget is recreated on every rebuild, but the State object survives. That is why a TextEditingController, an animation controller and so on live in the State, not in the widget.

Flutter actually keeps three trees, and the distinction comes up in interviews:

  • Widget tree — the configuration you write; cheap, recreated often
  • Element tree — the "live" instances of those widgets; holds state and position in the tree
  • Render tree — the layer that measures and paints

On rebuild Flutter compares the new widget tree with the old one and applies only the difference to the element and render trees. That is why build() being called often is not a problem in itself — doing heavy work inside build() is.

QuestionStatelessWidgetStatefulWidget
Internal mutable statenoneyes, in a `State` object
When it rebuildswhen the parent rebuilds italso when `setState` is called
Typical usean icon, a label, a static carda form, a counter, an animation
Resources and disposenot neededmust be cleaned up in `dispose()`

Interview tip. Only defining the two is a junior answer. A strong one adds the why: widgets are immutable, so mutable state lives in a separate State object that survives rebuilds. Finish with the practical consequence: "which is why I create controllers in `State` and close them in `dispose()`". If you want to go one step further, mention the three trees — most candidates do not know them.

📚 Sources and documentation