codingstairs
NotesEDULifeContact
⌕Search⌘K
koen

Navigation

  • Intro
  • Blog
  • Life

Get in touch

Send without signing in. Add your email if you'd like a reply.

  • Leave a message anonymously →
  • ✉ warragon112@gmail.com
  • KakaoTalk Open Chat ↗

© 2026 codingstairs

  • Notes
  • EDU
  • Search
  • Life
  • Contact
  • Legal
  • RSS
  • GitHub
Notes›mobile

Flutter Basics

Published 2026-04-28· Updated 2026-05-18·0 views

Flutter Basics

Flutter is a UI toolkit from Google that targets mobile, web, and desktop from a single codebase. Its own rendering engine, the Dart language, and the widget tree as an expression model are the core. This post covers Flutter's origins, the Dart language, the widget model, the rendering engines (Skia, Impeller), the build tooling, and the package ecosystem.

1. Flutter's origins

Event Time
Early demo known as "Sky" 2015
Flutter alpha (Sky renamed to Flutter) 2017
Flutter 1.0 GA 2018-12
Flutter 2.0 (web stable, null safety) 2021-03
Flutter 3.0 (macOS, Linux stable) 2022-05
Impeller renderer (iOS) default 3.10 (2023) ~ 3.13

Designed from the start with "one engine, every platform" as the goal. Instead of calling platform widgets, it draws every pixel through its own renderer.

2. Dart language

Event Time
Dart announced (Google) 2011
Dart 1.0 2013
Dart 2.0 (strong typing) 2018
sound null safety (opt-in) 2.12 (2021)
Dart 3.0 (sound null safety enforced, pattern matching, etc.) 2023-05

Dart began as a JavaScript alternative, but after Flutter adopted it, it found its place as a client UI language.

Characteristics:

  • C-family syntax, familiar to Java / JavaScript / TypeScript.
  • Both AOT (Ahead-Of-Time) and JIT (Just-In-Time) — JIT during development (hot reload), AOT for release (performance).
  • sound null safety — a variable's nullability is expressed in the type system.
  • Pattern matching, records, sealed classes (3.0+).
String greet(String? name) {
  return switch (name) {
    null => 'hello, friend',
    String s when s.isEmpty => 'hello, friend',
    String s => 'hello, $s',
  };
}

3. Widget tree

Flutter's expression model is the widget tree. The whole screen is built from widgets, and a widget's build output is again widgets:

class HelloApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Hello')),
        body: Center(child: Text('world')),
      ),
    );
  }
}
Kind Meaning
StatelessWidget Same input, same output. No internal state.
StatefulWidget Has its own state. The State object lives along the widget lifecycle.
class Counter extends StatefulWidget {
  @override
  State<Counter> createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () => setState(() => count++),
      child: Text('$count'),
    );
  }
}

When setState is called, the corresponding subtree rebuilds.

4. Widget · Element · RenderObject

Flutter internally uses three trees:

  • Widget Tree — lightweight configuration objects. Recreated frequently.
  • Element Tree — instances of widgets. They have a lifecycle and keep the mapping with the child tree.
  • RenderObject Tree — performs the actual layout and painting.

This separation keeps the cost of recreating widget objects low. Diffing happens in the element tree.

5. Rendering engines

Skia — Flutter started on Skia (the 2D graphics engine used by Chrome and Android). It can use both CPU and GPU, but Flutter mainly uses the GPU path.

Impeller — first-frame jank on iOS was reported often. One cause was Skia's shaders compiling on first appearance on screen. Impeller is a new renderer designed to fix this by precompiling shaders at build time:

  • iOS — default in 3.10 (2023).
  • Android — gradual enablement (defaulted on in stages between 3.16 and 3.27).
  • macOS · Web · Desktop — work in progress.

6. Development flow

Action Meaning
Hot Reload Inject only changed code. Widget tree is preserved, state too.
Hot Restart Restart the app. State is reset.

Hot Reload is what Dart's JIT enables. It shines when iterating quickly on UI details.

Build tools:

  • flutter create app — create a project.
  • flutter run — run on a device or emulator.
  • flutter build apk|ipa|web|windows|macos|linux — per-platform artefact.
  • flutter pub get — fetch packages.
  • flutter pub upgrade — update.
  • dart format · flutter analyze — format · lint.

The Mac · Linux and Windows commands are identical.

7. pub.dev and packages

The official Dart · Flutter package registry. Its scoring system (pikes) evaluates maintenance, platform compatibility, and documentation.

Category Packages
State management provider · riverpod · bloc · get_it
Routing go_router · auto_route
HTTP dio · http
Local DB sqflite · drift · isar · hive
Serialization json_serializable · freezed
Local storage shared_preferences · flutter_secure_storage
Push firebase_messaging

8. State management

Flutter itself only ships setState and InheritedWidget. Larger apps reach for external state-management packages:

  • Provider — started as the official recommendation. Simple.
  • Riverpod — the successor to Provider. Compile-time safety.
  • Bloc / Cubit — event → state flow. Strong on testability.
  • GetX — bundles dependencies, routing, and state. Simplicity is a strength; structural enforcement is a weakness.
  • MobX — a reactive model.

The choice depends on team familiarity and app size.

9. Platform channels · adaptive UI

Platform channels — when calling native code, use MethodChannel, EventChannel, BasicMessageChannel. iOS in Swift / Obj-C, Android in Kotlin / Java.

Adaptive UI — Cupertino widgets for iOS and Material widgets for Android come from separate libraries. Branch on Platform.isIOS or use abstraction packages like flutter_platform_widgets.

10. Common pitfalls

Bundle size — Hello World runs into several MB. Including its own engine is the cause. Text compression and code splitting aren't as flexible as they are on the regular web.

iOS first-frame jank — a common report before Impeller. Improved since, but spots with many custom shaders still need checking.

Missing platform widgets — new iOS · Android UI controls don't arrive instantly. Flutter has to catch up.

Accessibility tree — because it draws on its own, OS accessibility needs separate mapping. Missing labels make screen readers unreliable.

Web target limits — Flutter Web uses Skia (canvaskit) or HTML backends. Weaker than regular web frameworks for SEO indexing, accessibility, and bundle size.

State-management splintering — too many choices raise the decision cost. A team convention helps.

Dart package diversity — not as broad as Node or Python. Some areas need direct implementation.

OS-update compatibility — yearly SDK changes break some packages. Check library maintenance activity.

Closing thoughts

Flutter brings pixel-level consistency through its own-canvas model. Dart's sound null safety, pattern matching, and AOT / JIT support form the foundation. Limits include bundle size, keeping up with platform widgets, accessibility mapping, and weak web targets. It fits best where 60 / 120 fps animations matter or consistent pixels are part of the business value.

Next

  • android-build-apk
  • ios-build

Flutter official docs · Dart official docs · Flutter Codelabs · pub.dev · Impeller intro · Flutter Engine GitHub · Effective Dart · Flutter Samples for reference.

More in mobile

All in this category →
  • iOS App Build — Xcode · Signing · TestFlight
  • Android App Build — APK · AAB · Signing
  • Cross-platform Mobile — Comparing the Candidates