Flutter and Dart Deep — Impeller, WASM, and the Multi-Platform Engine
Flutter is the only cross-platform UI framework whose runtime ships its own renderer rather than wrapping platform views. The bet — that a Skia/Impeller-based GPU renderer + a hot-reload-friendly language + an opinionated widget catalog could match native fluidity on iOS, Android, Windows, macOS, Linux, web, and embedded — has paid off well enough that Flutter is now in vehicle infotainment (BMW, Toyota), Sony PlayStation system apps, Google’s own internal apps (Pay, Ads, Earth), Alibaba, ByteDance, and a long tail of consumer apps. The 2024-2026 release cohort (Flutter 3.16 through 3.27+ with Dart 3.3 through 3.7+) completed the Impeller migration on iOS and Android, brought WASM/WebGPU to web, and stabilised dart2wasm. This note covers the rendering pipeline, the Dart language and its concurrency model, the widget/state-management ecosystem, persistence, platform-interop FFI/Pigeon, and the deployment surface across all seven target platforms.
See also
- concurrency-primitives — Dart isolates contrasted with shared-memory threading.
- compiler-design — Dart’s dual AOT/JIT compilation, dart2wasm, dart2js.
- garbage-collection — Dart’s generational GC tuned for UI workloads.
- cpu-cache-performance — Impeller’s tessellation + GPU pipeline performance characteristics.
- cuda-triton-gpu-programming — GPU compiler / shader compilation context (Impeller’s SkSL → SPIR-V transform).
- observability-stack — Sentry, Firebase Crashlytics, DevTools integration.
- sql-nosql-design — drift, sqflite, Isar, ObjectBox.
- inference-optimization — TFLite via flutter_tflite, ONNX Runtime in Flutter.
1. The Dart language in 2026
1.1 Dart 3 and sound null safety
Dart 3 (May 2023) made sound null safety mandatory — there is no opt-out. The type system distinguishes String (non-nullable) from String? (nullable); the compiler enforces null checks at every dereference. Dart 3 also removed legacy mode entirely; the migration tool dart fix --apply and dart migrate are obsolete.
1.2 Records, patterns, sealed classes (Dart 3.0+)
// Records — anonymous typed tuples.
(int, String) pair = (1, 'one');
final (int count, String name) = pair; // destructure
// Pattern matching in switch expressions.
String describe(Shape s) => switch (s) {
Circle(:final radius) => 'circle radius=$radius',
Square(:final side) => 'square side=$side',
};
// Sealed classes for exhaustive switches.
sealed class Shape { }
class Circle extends Shape { final double radius; Circle(this.radius); }
class Square extends Shape { final double side; Square(this.side); }Patterns also work in if-case, final destructuring, and function parameter destructuring. Sealed classes provide compile-time exhaustiveness checking in switch expressions.
1.3 Extension types (Dart 3.3)
Zero-cost wrappers around an existing type. Compile-time-only — no allocation overhead — but provide a distinct type for API safety:
extension type UserId(String value) { }
extension type ProductId(String value) { }
// UserId and ProductId are distinct at compile time even though both wrap String.Replaces the legacy “wrap in a class” pattern and the failed extension methods on classes. Used widely in Flutter framework internals (e.g., OpenUnaryFunction).
1.4 Compilation modes
Dart compiles three ways:
- AOT (Ahead-of-Time).
dart compile exe,flutter build apk/ipa/macos/windows/linux. Produces native machine code; fastest runtime; long startup-to-first-frame budget. - JIT (Just-in-Time).
dart run,flutter run(debug builds). Hot reload and hot restart depend on JIT. - dart2js. Compile to JavaScript for web. Standard for Flutter Web until Wasm became default.
- dart2wasm (Dart 3.0+, stable 3.5 in 2024). Compile to WASM-GC + JS interop. Used by Flutter Web Wasm builds. Performance: 2-3× faster than dart2js for compute-heavy workloads; comparable for UI-heavy.
1.5 Concurrency: isolates and Futures
Dart has no shared-memory threading. Concurrency primitives:
- Future
and async/await. Single-threaded cooperative concurrency on the event loop. - Stream
. Async sequence; broadcast and single-subscription variants. - Isolate. Heap-isolated worker.
Isolate.spawn(...)creates a new isolate with its own heap and GC; communication viaSendPort/ReceivePort(message passing only, no shared memory). - compute(fn, arg). Flutter helper that spawns a short-lived isolate, runs
fn(arg), returns the result. Used for heavy JSON parsing, image processing, cryptography.
Dart 2.15 added isolate groups — multiple isolates that share the same code segment and GC heap structure, reducing spawn cost. Dart 3.0+ supports passing more types across isolate boundaries (not just SendPortable types).
The single-threaded UI model is a design choice: Flutter’s renderer runs on the UI isolate; expensive work runs on background isolates; results post back via messages. The model maps cleanly to React’s single-threaded JS model but offers true parallelism for compute work.
1.6 Foreign function interface
- dart:ffi. Direct C ABI calls. Used for SQLite, libuv, libsodium, custom native dependencies.
- ffigen. Generates Dart FFI bindings from C headers (uses LLVM clang). Drives most production FFI usage.
- jnigen (Dart 3.x). Generates Dart bindings from Java/Kotlin classes; calls JVM/ART methods directly. Enables Java-only libraries to be used from Flutter without a method-channel hop.
- flutter_rust_bridge (community, very popular). Generates Dart bindings from Rust types and functions; bidirectional callbacks, error propagation. Used by Bitwarden mobile, Polkadot wallets, many crypto apps.
2. Flutter rendering: from Skia to Impeller
2.1 The legacy Skia renderer
From Flutter’s launch through ~2023, the engine wrapped Google Skia (the same 2D library used by Chrome, Firefox, Android). Skia’s draw calls translated to OpenGL / Metal / Vulkan via per-frame shader compilation; shader compilation jank — the first frame using a new draw call could stall hundreds of milliseconds while the GPU driver compiled the shader — was a long-standing Flutter complaint. Workarounds (SkSL warmup) shipped specific shaders to disk during onboarding flows; brittle and per-device.
2.2 Impeller
Impeller (announced 2022, default on iOS in Flutter 3.10 May 2023, default on Android in Flutter 3.16+ with Vulkan-supporting devices) replaces Skia. Architecture:
- No runtime shader compilation. All shaders are precompiled at engine build time (offline) from a fixed shader set. Eliminates per-frame jank.
- Tessellation pipeline. Paths converted to triangle meshes on CPU; uploaded once; GPU consumes them with simple shaders.
- Per-platform GPU backend. Metal on iOS/macOS, Vulkan on Android/Linux, OpenGL ES fallback on Android Vulkan-less devices, DirectX/Direct3D 11/12 in progress on Windows.
- Glyph atlas. Text glyphs rasterised on demand and cached; SDF (signed distance field) variant for animated text.
- Stable command buffer model. Each frame submits a deterministic sequence of GPU commands; testable and profilable.
Impeller’s first-frame perf is comparable or slightly slower than Skia for static content (more CPU tessellation) but dramatically better for animated content (no shader stalls). Memory usage is slightly higher (more textures cached). The Impeller team continues to optimise per-platform; the trajectory is convergent with Skia for static, dramatically ahead for dynamic.
2.3 WebGPU (experimental)
Flutter Web’s Wasm builds can opt into a WebGPU rendering backend (--web-renderer canvaskit is default; an experimental --web-renderer skwasm ships, and an Impeller-on-WebGPU path is in design as of 2025). Performance roughly matches native Skia for typical apps.
2.4 The three trees
Flutter renders in three parallel trees:
- Widget tree. Immutable description of “what should be visible.” Built by the developer via
build(context)methods. - Element tree. Mutable per-frame; mirrors the widget tree’s structure. Elements own State objects, manage the rebuild lifecycle.
BuildContextis a reference to an Element. - RenderObject tree. The layout + paint tree. Handles constraints-go-down + sizes-go-up layout, paint ordering, hit testing.
Reconciliation: a new widget tree from setState() is diffed against the existing element tree by widget type + key; matched elements update their associated render objects; unmatched elements are disposed. The render-object tree (heavyweight) only changes when widget type or key changes.
3. State management
The Flutter ecosystem has cycled through libraries; the 2026 status:
- Riverpod 3 (Remi Rousselet). Successor to Provider. Compile-time-safe providers, no BuildContext dependency for non-widget code, sound disposal. Recommended default for new apps. v3 (late 2024) added code generation via
riverpod_generator. - Provider. Riverpod’s predecessor; still maintained by the same author; recommended for very simple apps or back-compat.
- Bloc / Cubit (felangel). Event/state machine pattern.
bloc_test, hydrated_bloc for persistence. Used by larger teams that value the explicit event model; can be verbose for small features. - GetX. All-in-one (state + routing + DI + utilities). Popular outside the Western Flutter community; has structural critiques around testability.
- MobX. Observable-based; codegen via
build_runner. Less common than Riverpod but viable. - Redux. Niche.
- StateNotifier + Provider. Riverpod’s predecessor; effectively replaced by Riverpod’s
NotifierandAsyncNotifier. - signals_flutter. Solid.js-style fine-grained signals; growing mindshare in 2024-25.
Pattern: Riverpod for new apps; Bloc for teams that already use it; Provider for legacy.
4. Routing
4.1 go_router v14
Built on Navigator 2.0 (Flutter 1.22, 2020) which exposed the navigation stack as state instead of the imperative Navigator.push/pop (Navigator 1.0). go_router (Flutter team, maintained as official package) provides declarative URL-based routing:
final router = GoRouter(
routes: [
GoRoute(path: '/', builder: (c, s) => HomeScreen()),
GoRoute(
path: '/profile/:id',
builder: (c, s) => ProfileScreen(id: s.pathParameters['id']!),
),
],
);Type-safe routes via the go_router_builder codegen package. Deep linking, URL strategy (path vs hash on web), shell routes (nested navigators sharing chrome), redirect logic.
4.2 auto_route, Beamer
- auto_route. Codegen-heavy alternative with strong typing.
- Beamer. Less common; designed for very URL-driven apps.
Navigator 1.0 (Navigator.push(context, MaterialPageRoute(...))) still works and is fine for small apps; large apps should use go_router for deep-link and back-button consistency.
5. Networking and data
- http. Built-in HTTP client. Minimal.
- dio. Feature-rich HTTP wrapper with interceptors, retry, multipart, transformers. The de-facto standard.
- ferry. Type-safe GraphQL client with codegen; less heavy than graphql_flutter.
- graphql_flutter. Apollo-derived GraphQL client.
- chopper, retrofit.dart. Retrofit-style HTTP wrappers.
- WebSocket. Built-in
WebSocketclass;web_socket_channelpackage for cross-platform.
6. Persistence
6.1 SQLite-backed
- drift (Moor renamed). Reactive ORM with compile-time query checking and codegen. Excellent typing. Recommended default for SQL-heavy apps.
- sqflite. Low-level SQLite wrapper. Used directly when codegen is undesired.
6.2 Object databases
- Isar. Pure Dart NoSQL DB; fast, supports indexes, fulltext search. The author paused development in 2023-24 (Isar 3); community is forking. Production-stable.
- ObjectBox. Cross-platform object database; faster than Isar for raw I/O; commercial backing.
6.3 KV and config
- shared_preferences. Built-in KV; UserDefaults / SharedPreferences / Registry per platform.
- hive. Pure Dart KV with binary encoding; faster than shared_preferences; popular for small caches.
- flutter_secure_storage. Wraps Keychain/Keystore for secrets.
6.4 Realm
MongoDB Realm Flutter SDK. Sync to MongoDB Atlas Device Sync; declining mindshare since MongoDB’s 2022 deprioritisation.
6.5 firebase_core + cloud_firestore
Firebase Firestore wrappers are common in Flutter apps that already use Firebase Auth / Functions / Hosting; offline cache and real-time listeners work well.
7. Platform integration
7.1 Platform channels
The original Flutter-to-native bridge. MethodChannel for one-shot calls, EventChannel for streaming events, BasicMessageChannel for binary messages. Manual codec implementation on both sides; brittle for complex types.
7.2 Pigeon (recommended for new code)
Code-generation tool that takes a Dart spec file and emits Kotlin/Swift/C++ host code and Dart client code with type-safe method signatures. Eliminates the manual MethodChannel string-method-name dance:
@HostApi()
abstract class ContactsApi {
List<Contact> getAll();
Future<Contact> get(String id);
}Pigeon runs at build time (dart run pigeon --input pigeon.dart). The community standard since 2022.
7.3 FFI for native libraries
C libraries (SQLite, libsodium, ICU) consumed directly via dart:ffi + ffigen. Skips the platform-channel cost for high-frequency calls.
7.4 jnigen (Android-specific Java/Kotlin)
Generates Dart bindings from Java/Kotlin class files. Useful when consuming Android-only libraries that don’t have a Flutter wrapper.
7.5 flutter_rust_bridge
The most popular cross-language wrapper after Pigeon. Generates Dart bindings from Rust types/functions; supports streams, async, structs, enums. Used to embed Rust crypto, image processing, or business logic into Flutter apps.
8. Animations
- AnimatedBuilder, AnimationController, Tween. Built-in primitives. Verbose but composable.
- TweenAnimationBuilder. Declarative; tweens a value over a duration.
- Hero. Shared element transitions across routes.
- flutter_animate (Gustavo Cordeiro). Chainable animation API; minimal boilerplate.
- Rive (rive_flutter). Vector animation runtime; designers author in Rive editor.
- Lottie (lottie package). After Effects animations.
- Flame. 2D game engine on Flutter. Used for many indie games and edutainment apps.
- flutter_3d_controller, ar_flutter_plugin. 3D and AR.
9. The rendering pipeline in detail
9.1 Build phase
setState() marks the element dirty. On the next frame, Flutter walks dirty elements, calls build(), gets a new widget; diffs against the existing widget by == and runtimeType; updates the element’s reference. Cheap (immutable widgets).
9.2 Layout phase
The render-object tree walks top-down passing constraints (BoxConstraints); each render-object selects its size within the constraints; sizes propagate bottom-up. Sublinear in practice because RenderObjects cache their layout when constraints + state are unchanged.
9.3 Paint phase
Render-objects record draw commands into a PictureRecorder → Picture. The engine assembles a Scene from layer tree and submits to Impeller.
9.4 Composite phase
Impeller takes the Scene, walks the layer tree, issues GPU commands. The platform’s compositor (CoreAnimation on iOS, SurfaceFlinger on Android) merges Flutter’s output with system UI (status bar, navigation bar, other apps).
9.5 Frame budget
60 Hz devices have 16.6 ms per frame; ProMotion / 120 Hz devices have 8.3 ms. Flutter’s “Performance overlay” (debug builds, MaterialApp(showPerformanceOverlay: true)) shows two bars: UI thread + GPU thread. Bars rising above the budget line indicate jank.
10. Deployment across seven platforms
10.1 Mobile (iOS, Android)
flutter build apk— universal APK.flutter build appbundle— Android App Bundle (required by Play).flutter build ipa— iOS archive (.xcarchive+.ipa).- Subsequent submission via fastlane, EAS-style services, or directly through App Store Connect / Play Console.
10.2 Desktop (Windows, macOS, Linux)
flutter build windows—.exe+ supporting DLLs inbuild\windows\runner\Release\.flutter build macos—.appbundle; package as.dmgviacreate-dmgordmgbuild.flutter build linux— ELF binary + shared libraries.
Distribution: Microsoft Store (MSIX), Mac App Store, Apple Developer ID + notarisation, Snap/Flatpak/AppImage for Linux.
10.3 Web
flutter build web— JS-based output (dart2js).flutter build web --wasm— Wasm-GC output (dart2wasm). Recommended for new web deployments since Flutter 3.22 (May 2024).
Renderer: CanvasKit (Skia compiled to Wasm, default), HTML (DOM-based, retired in Flutter 3.27 late 2024), or experimental WebGPU (in design).
10.4 Embedded
Flutter embeds run on Yocto Linux for in-vehicle systems (BMW iX iDrive, Volkswagen ID-series infotainment via Cariad, Toyota Smart Cockpit), STM32-class microcontrollers via flutter-elinux, Sony PlayStation 5 system UI components, and Kindle Scribe note-taking. Embedding API exposes platform-channel surface for host integration.
11. CI / build services
- Codemagic. Flutter-first hosted CI; macOS + Linux + Windows runners; out-of-the-box Flutter caching.
- Bitrise. Cross-platform CI with Flutter step library.
- Fastlane. Used for iOS/Android publishing steps (gym, supply, pilot).
- GitHub Actions. Run Flutter on ubuntu-latest / macos-latest / windows-latest with
subosito/flutter-action. - Firebase App Distribution + TestFlight. Beta distribution.
12. Production case studies (2024-2026)
- BMW iX, i7 (2022+). Digital cockpit (instrument cluster + infotainment) built on Flutter Embedded. ~100 engineer-years invested per BMW public talks.
- Toyota Smart Cockpit (2024+). Next-gen vehicle UI; partnership announced at GDC 2023.
- Sony PlayStation 5 game streaming UI. Confirmed via Flutter Forward 2023.
- Alibaba Xianyu (Idle Fish). ~50M users; one of the largest Flutter apps by user count.
- ByteDance. Multiple internal Flutter apps including parts of Douyin’s creator tools.
- Tencent. Several productivity apps.
- Google. Google Pay (Android), Google Ads, parts of Google Classroom, Google Earth Studio.
- eBay Motors.
- Square Cash for Business (parts).
- Yandex Go (Russian Uber equivalent).
- iRobot Roomba app.
- Reflectly, Hamilton (musical app), New York Times Crosswords (parts).
- Wonderous (Google’s showcase app).
Apps that left Flutter: notable instance is Flutter’s own absence from some Google-owned apps (Gmail, YouTube) which remain native; some smaller dev teams have moved off after hitting platform-specific feature blockers (CarPlay, deep WearOS integration). The trend is firmly toward adoption.
13. Flutter Web and Server-Driven UI
13.1 Web
flutter build web --wasm is the recommended 2026 path. Caveats:
- Initial download size: ~2-4 MB gzipped for a hello-world Wasm build; ~5-10 MB for a typical app. Lazy-load secondary routes via deferred imports.
- SEO: not great. Flutter Web renders to canvas; HTML semantic accessibility is via a hidden DOM mirror. Server-side rendering is not native; usage as a PWA + static landing page combo is common.
- Strong fit: dashboards, design tools (Rive), interactive media (game-like UIs), apps where cross-platform parity matters more than SEO.
13.2 Remote Flutter Widgets (Server-Driven UI)
Google’s rfw package serialises a widget tree to JSON-like format, rendered client-side. Used by Google internal teams to ship UI updates without app-store re-review. Pattern adopted by Lyft, Airbnb (returning), and others for promotions and onboarding.
14. Tooling
14.1 DevTools
Flutter DevTools (flutter pub global activate devtools && devtools) is the hosted Chrome-based debugger. Panels:
- Inspector. Widget tree visualiser, layout debugger.
- Performance. Frame timeline, raster + UI thread breakdown.
- CPU Profiler. Sampling profiler with flame charts.
- Memory. Heap snapshots, leak tracker.
- Network. HTTP requests.
- Logging. print + logger output.
Integrates with Android Studio, VS Code, IntelliJ.
14.2 Hot reload vs hot restart
- Hot reload. Re-injects updated source into the running isolate, preserves state. Sub-second.
- Hot restart. Restarts the isolate, loses state. Few seconds.
Available only in debug (JIT) mode. Production AOT builds have no hot reload.
14.3 Linting
flutter_lints is the official lint set. Stricter alternatives: very_good_analysis (Very Good Ventures), pedantic (deprecated).
14b. Pub.dev and the package ecosystem
Pub.dev (pub.dev) is the canonical Dart package registry. ~50,000+ packages as of 2025. Quality signals:
- Dart-team verified publisher. Blue checkmark next to flutter.dev / google.dev / dart.dev-published packages.
- Likes, popularity, pub points. 130-point quality score (static analysis cleanliness, dependency freshness, documentation completeness, example coverage).
- Platform compatibility badges. Per-platform support (iOS, Android, Web, Windows, macOS, Linux).
- Null safety badge. Mandatory since Dart 3; older packages without it are effectively dead.
Production hygiene: pin direct dependencies to caret ranges (^1.2.3); commit pubspec.lock; review dependency updates in PRs. The dart_code_metrics and dependency_validator packages catch missing/extraneous dependencies and code-quality issues at scale.
14c. melos and monorepo tooling
melos (Invertase) is the de-facto Flutter monorepo orchestration tool. Manages multi-package projects: per-package flutter pub get, parallel test runs, version bumping coordinated across interdependent packages. Common pattern: apps/ for shipping apps, packages/ for shared internal libraries (design system, networking core, feature modules), tools/ for build scripts.
Example melos.yaml:
name: my_monorepo
packages:
- apps/**
- packages/**
scripts:
analyze: melos exec -- dart analyze
test: melos exec --concurrency 4 -- flutter testAlternative monorepo tools: mason (templating + brick generation, also Invertase), very_good_cli (Very Good Ventures scaffolding).
14d. Build modes and tree shaking
Three build modes:
- Debug. JIT, hot reload, assertions on, verbose logging.
flutter run. - Profile. AOT, debug tools enabled but assertions off, performance-similar to release.
flutter run --profile. For profiling on real devices. - Release. AOT, assertions off, debug tools disabled, full tree shaking + minification.
flutter run --release,flutter build *.
Tree shaking happens at the Dart AOT compilation step. Unused functions, unused classes, unused fields — all removed. Reflection (dart:mirrors) is explicitly unsupported in AOT for exactly this reason; the compiler must statically prove what’s used. Code that pulls in dart:mirrors won’t compile for Flutter.
Icon font tree-shaking: Flutter builds custom icon fonts containing only the icons actually referenced via Icons.foo. Saves ~1 MB on apps using Material Icons.
15. Common pitfalls
- setState in build method. Triggers infinite rebuild. The framework asserts, but only in debug.
- BuildContext after async. Using
contextafterawaitmay reference a disposed widget; use themountedcheck. - Massive widget trees. Building 5000-row ListView with non-virtualised children is the most common perf bug; use ListView.builder.
- Image OOM on lists. Default Image widget caches eagerly; use cached_network_image + ListView.builder + dispose properly.
- Unbounded constraints.
Column { Container() }insideSingleChildScrollViewwithoutmainAxisSize: minerrors at layout time with “vertical viewport was given unbounded height.” - Isolate startup cost. First
compute()call is ~50-100 ms (isolate spawn). For frequent short tasks, use a long-lived isolate viaIsolate.spawn+ a ReceivePort. - dart:ffi pointer lifecycle. Manual malloc/free; leaks cause memory growth. Use Arena (package:ffi) for scoped allocation.
- Web wasm bundle size. Profile with
flutter build web --wasm --analyze-sizeand lazy-load. - Mixing Material 2 and Material 3 widgets. Migrate per-screen; mixing in one screen breaks theme inheritance.
15b. Isolates pattern for compute work
Future<List<Person>> parseUsers(String json) async {
return compute(_parse, json);
}
List<Person> _parse(String json) {
final list = jsonDecode(json) as List;
return list.map((m) => Person.fromJson(m as Map<String, dynamic>)).toList();
}compute(fn, arg) spawns a one-shot isolate, runs fn(arg), returns the result. Use for parsing JSON >100 KB, image processing, crypto, regex over large strings — anything that would block the UI for >16 ms.
Long-lived isolate pool (custom): spawn N isolates at app start; send work via SendPort; receive results via ReceivePort. Tools like the isolate_pool_2 and worker_manager packages wrap the boilerplate.
The trade-off: cross-isolate communication copies data (sendable types only). Large objects copied frequently nullify the parallelism benefit. Use TransferableTypedData for zero-copy transfer of byte buffers; available since Dart 2.6.
15c. Theming and design tokens
Flutter’s ThemeData (Material 3) and CupertinoThemeData (iOS-style) provide theme inheritance. Custom themes via ThemeExtension<T> (Flutter 3.7+):
class AppTheme extends ThemeExtension<AppTheme> {
final Color brand;
AppTheme({required this.brand});
@override AppTheme copyWith({Color? brand}) => AppTheme(brand: brand ?? this.brand);
@override AppTheme lerp(ThemeExtension<AppTheme>? other, double t) =>
AppTheme(brand: Color.lerp(brand, (other as AppTheme).brand, t)!);
}
// MaterialApp(theme: ThemeData(extensions: [AppTheme(brand: Colors.blue)]))
// Read via: Theme.of(context).extension<AppTheme>()!.brandPattern: define a set of design tokens (colour roles, type scale, spacing scale, radius scale, shadow scale); generate Flutter ThemeData from a JSON token file at build time via a custom build_runner script or via the design_tokens package.
Dark mode: ThemeMode.system follows OS; Theme.of(context).brightness checks current. Image assets via .dark-suffixed variants in pubspec.yaml.
16. Compared to React Native, Native, Capacitor
See react-native-deep for RN; capacitor-pwa-and-cross-platform-web for Capacitor/Tauri. Quick orientation:
- Flutter vs RN. Flutter renders custom; RN renders to native widgets. Flutter is more consistent across platforms; RN looks more native by default. Flutter’s perf ceiling is higher (controlled GPU pipeline); RN’s developer experience is more familiar to web devs.
- Flutter vs native. Flutter wins on cross-platform engineering cost; native wins on platform-specific feature speed (latest CarPlay, latest watchOS, latest VisionOS APIs land in native first).
- Flutter vs Capacitor/Tauri. Different categories. Flutter is for apps where graphics fluidity matters; Capacitor for web-tech apps that need a native shell.
17. On-device ML and Firebase
- flutter_tflite, tflite_flutter. TFLite (LiteRT) wrappers; CPU and NNAPI/Metal/CoreML delegates.
- google_mlkit_*. ML Kit (Google) packages: text recognition, face detection, barcode scanning, pose detection, image labelling. Pre-built models that run on-device.
- onnxruntime. Cross-platform ONNX Runtime; less common than TFLite in Flutter apps.
- firebase_ai_logic / vertexai_dart. Firebase Vertex AI for cloud-served LLMs.
- flutter_gemma. Wraps Google’s on-device Gemma Nano model via MediaPipe.
The integration pattern is typically: Pigeon-generated bridge to a platform-specific ML runner that loads the model file, exposes prediction methods. Performance is bound by the underlying platform runtime; Flutter adds millisecond-scale overhead via the platform-channel call.
See inference-optimization for the cross-platform mobile ML landscape including the LiteRT (TensorFlow Lite renamed late 2024) per-vendor delegate model that Flutter apps inherit.
18. Testing
- Unit tests. Plain Dart in
test/folder;flutter test. Mock dependencies viamocktail(Felangel) ormockito. - Widget tests. Build a widget tree, fire events, assert state — without a real device.
testWidgets('foo', (tester) async { ... }). Run as plain Dart but get a fake render tree. - Integration tests. Real device / emulator end-to-end.
integration_testpackage; run viaflutter test integration_test. - Golden tests. Pixel-compare widget output against committed reference PNG.
matchesGoldenFile('foo.png'). Critical for design-system regression; CI must run on the same renderer (CanvasKit vs Skia) used to generate goldens. - Patrol (LeanCode). Native-aware integration testing; can tap system dialogs (permission prompts, notifications) that
integration_testcan’t reach. - Maestro. YAML-defined cross-platform UI tests; popular for Flutter + RN + native shops.
- Firebase Test Lab. Cloud device farm; runs Flutter integration tests on real iOS + Android devices.
Further reading
- Flutter Documentation (flutter.dev/docs) — canonical reference.
- Dart Language Tour (dart.dev/language).
- Flutter Engineering (Flutter team blog).
- Tim Sneath, Eric Seidel — Flutter Forward keynotes 2023-2024 (Impeller, Wasm rollouts).
- Remi Rousselet — Riverpod docs and YouTube talks.
- Filip Hracek — Flutter Casts (YouTube).
- Real World Flutter by Tutorials (raywenderlich.com / Kodeco).
- Flutter Apprentice (Kodeco).
- Flutter Engage and Flutter Forward conference videos.