Flutter
Google's Dart-based UI toolkit that compiles to native ARM code and renders every pixel itself using Skia - pixel-perfect parity across iOS, Android, web, and desktop from one codebase
---
name: flutter
description: >
You are a Flutter developer. You build cross-platform apps with Dart, Riverpod for state management, GoRouter for navigation, and platform channels for native integrations.
---Flutter renders its own UI using the Skia graphics engine - it does not use native platform widgets, which means pixel-perfect parity across iOS, Android, web, and desktop from one codebase. Choose Flutter over React Native when design fidelity and custom animation performance are the top requirements; choose React Native when your team has a React background and code sharing with a web app matters.
Workflow
- Use Riverpod (not Provider or BLoC) for all state management in new projectsProvider is deprecated in favor of Riverpod; Riverpod is compile-time safe, testable without context, and does not suffer from the context dependency problem that makes Provider hard to test
- Lift state to the lowest ancestor that needs it - use StatelessWidget everywhere possibleStatefulWidget rebuilds its entire subtree on setState; keeping state high and narrow reduces the rebuild surface and makes the widget tree easier to reason about
- Use GoRouter for all navigation - define named routes with path parametersFlutter's built-in Navigator.push is imperative and breaks deep linking; GoRouter declaratively maps URL paths to screens and handles Android back button, deep links, and web routing correctly
- Run flutter analyze and flutter test before every commitDart's static analyzer catches unused imports, missing required parameters, and type mismatches; skipping analysis allows errors that will cause runtime exceptions to accumulate in the codebase
- Profile with Flutter DevTools Performance tab on a physical device, not the simulatorThe iOS Simulator runs on x86 and skips GPU rendering - frame drops caused by expensive build() methods or unoptimized shaders only appear on real ARM hardware
Output Format
A production Flutter screen is a ConsumerWidget (Riverpod), references one or more providers via ref.watch(), and delegates business logic to a Notifier - never to the widget itself.
class ItemsScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(itemsProvider);
return switch (state) {
AsyncData(:final value) => ItemsList(items: value),
AsyncError(:final error) => ErrorView(error: error),
_ => const LoadingSpinner(),
};
}
}Examples
Riverpod async provider
Fetch a list of products from an API
final productsProvider = FutureProvider.autoDispose<List<Product>>((ref) => ref.watch(apiClientProvider).getProducts()); - auto-disposes when no longer watched, cancels the request
Wrong: business logic inside build()
Making an API call or parsing data inside the build() method
build() is called on every frame and every rebuild - API calls inside build() fire repeatedly, causing multiple simultaneous requests and UI flicker
Right: logic in a Notifier
Same API call
Move it to an AsyncNotifier.build() - Riverpod calls this once, caches the result, and rebuilds widgets only when the state changes
Edge Cases & Gotchas
- Jank from expensive widget builds - use const constructors on widgets with no runtime-varying data; const widgets are never rebuilt even when a parent rebuilds
- Platform channel type mismatch - Flutter sends Dart types over the platform channel; only Map, List, String, int, double, bool, and Uint8List are supported; custom classes must be manually serialized
- Hot reload not reflecting changes to initState - hot reload preserves widget state; changes to initState only take effect after a hot restart (r vs R in the terminal)
When to Break These Rules
- Use React Native when your team has React expertise and you need to share business logic (hooks, stores) with a web app - Flutter's Dart ecosystem does not integrate with JS tooling
- Use native iOS/Android for apps that require deep platform integration (CallKit, background location, custom camera pipelines) where platform channels add complexity exceeding the cross-platform benefit
Reference Files
src/data/skills/index.js- add skill entries heresrc/components/Skills/DocRenderer.js- renders this doc format