Learn Flutter - Core Concepts & Flutter Architecture
Episode 2 of 23

Learn Flutter - Core Concepts & Flutter Architecture

This episode dissects the Flutter architecture: how Widgets, the rendering engine, and the Dart runtime work together, the reactive UI model and widget lifecycle, the relationship between the widget tree, element tree, and render tree, and the JIT and AOT compile model with hot reload.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

In episode 1 you learned why Flutter draws its own UI. Now we move to the next layer: how Flutter works under the hood. Understanding the architecture is what separates a developer who merely stacks widgets from one who can debug complex problems.

Episode 2 dissects four pillars of the Flutter architecture: the roles of widgets, the rendering engine, and the Dart runtime; the reactive UI model and widget lifecycle; the relationship between three trees that work together — the widget tree, element tree, and render tree; and the JIT and AOT compile model that powers hot reload.

Widgets, Rendering Engine, and Dart Runtime

Three Core Layers

Flutter is composed of three layers that work side by side:

  • Widget framework: the library of widgets and layouts you write every day, written in Dart.
  • Rendering engine: executes layout, painting, and compositing — currently via Skia and Impeller.
  • Dart runtime: executes Dart code with a garbage collector and isolate management.
The smallest widget in Flutter
import 'package:flutter/material.dart';
 
void main() {
  runApp(const MyApp());
}
 
class MyApp extends StatelessWidget {
  const MyApp({super.key});
 
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: Center(
          child: Text('Halo Flutter'),
        ),
      ),
    );
  }
}

The code above is a complete Flutter application. runApp(MyApp()) attaches the widget to the screen, then the framework builds the widget tree downward. Notice that MaterialApp, Scaffold, Center, and Text are all widgets.

The Reactive UI Model and Widget Lifecycle

The UI Is a Function of State

Flutter uses a reactive model: a widget is a declaration of the UI for a given state. When state changes, build is called again and the framework updates the screen efficiently — you don't write imperative commands to mutate the UI.

The StatefulWidget Lifecycle

Stateful widgets have a well-defined lifecycle. The methods you'll use most often:

  • initState — called once when the widget is inserted into the tree.
  • didUpdateWidget — called when the parent replaces the widget's configuration.
  • dispose — called when the widget is removed; the place to clean up resources.
StatefulWidget with a basic lifecycle
import 'package:flutter/material.dart';
 
class CounterPage extends StatefulWidget {
  const CounterPage({super.key});
 
  @override
  State<CounterPage> createState() => _CounterPageState();
}
 
class _CounterPageState extends State<CounterPage> {
  int _count = 0;
 
  @override
  void initState() {
    super.initState();
    print('Widget dipasang');
  }
 
  @override
  void dispose() {
    print('Widget dibuang');
    super.dispose();
  }
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Counter')),
      body: Center(child: Text('$_count')),
      floatingActionButton: FloatingActionButton(
        onPressed: () => setState(() => _count++),
        child: const Icon(Icons.add),
      ),
    );
  }
}

setState in the example above tells the framework that state has changed, so build runs again. This is the cycle you'll master in episode 6 when we discuss state management.

The Widget Tree, Element Tree, and Render Tree

Three Trees Running Together

Flutter works with three structures at once:

  • Widget tree: the immutable configuration you write.
  • Element tree: the bridge that manages the lifecycle and instances of widgets, and the source of BuildContext.
  • Render tree: the objects that actually perform layout and painting.

When your build code runs, Flutter hydrates the widget tree into the element tree, then the render tree computes sizes and paints. Flutter's core optimization: when the tree is rebuilt, only the changed parts are marked as dirty and re-rendered — the rest is skipped.

Why BuildContext Matters

Every widget has a BuildContext that comes from its element. The context is used to look up ancestor widgets, navigate, read the theme, and much more. Understanding that context is an element, not a widget, explains many strange errors early in your Flutter learning journey.

The Compile Model: JIT, AOT, and Hot Reload

Two Modes for Two Needs

Flutter uses two Dart compile modes:

  • JIT during development (flutter run): enables hot reload and hot restart.
  • AOT for release (flutter build): code is compiled to machine code, resulting in fast startup and runtime.

The Workflow JIT Enables

With JIT, you change code and press r in the terminal to immediately see the result on the emulator without a full restart:

Run in release mode with AOT
flutter run --release

flutter run --release activates AOT mode: the app is built with full optimization, suitable for measuring real performance. Don't use this mode during development, because you lose hot reload.

Verifying code quality before committing also uses the Flutter toolchain:

Static analysis of Dart code
dart analyze

dart analyze detects potential problems in your code without running it — a habit that will save you a lot of debugging time.

Conclusion

Key takeaways:

  • The Flutter architecture consists of the widget framework, rendering engine, and Dart runtime.
  • The UI is reactive: build is called again whenever state changes.
  • StatefulWidget has a lifecycle: initState, didUpdateWidget, and dispose.
  • The widget tree, element tree, and render tree work together for layout and painting.
  • JIT powers hot reload; AOT delivers release performance.
  • Use dart analyze regularly before committing.

In the next episode 3 we get hands-on: installation and project setup — installing the Flutter SDK with environment verification, creating a new project with flutter create, exploring the generated project structure (lib, pubspec.yaml, android, ios, web), and running your first app on an emulator or device. You start actually touching code.