When I started building Let’s Discover Germany, I expected Flutter’s write once, run anywhere promise to make things straightforward. It largely delivered — but there were enough sharp edges to fill a blog post.
State Management: Don’t Over-Engineer Early
The most common mistake I see Flutter newcomers make is reaching straight for complex state solutions like BLoC or Riverpod before understanding the problem. For a mid-sized app, Provider with ChangeNotifier was more than sufficient. I only migrated to Riverpod later once the app grew, and that migration was painless because the logic was already well-encapsulated.
Rule of thumb: start with setState for local UI state, Provider for shared state, and only escalate when you feel genuine pain.
Firebase Real-Time Database vs Firestore
I initially chose Firebase Realtime Database because of its simplicity. The flat JSON structure works fine for small datasets, but as soon as I introduced nested data (places → reviews → users), queries became awkward and data denormalization became unavoidable.
If I were starting today, I’d go straight to Firestore. The document/collection model maps cleanly to how you think about your data, and compound queries save a lot of client-side filtering work.
Platform-Specific UI Pitfalls
Flutter renders its own widgets — it doesn’t use native components. This is its biggest strength and its biggest frustration:
- Fonts: The system font on Android and iOS differ. Loading a custom Google Font early sidesteps this.
- Navigation gestures: iOS users expect swipe-back; Flutter’s
CupertinoPageRoutehandles this, but mixingMaterialPageRouteandCupertinoPageRoutein the same app leads to inconsistent behavior. - Keyboard overlaps: On Android,
resizeToAvoidBottomInset: trueis your friend. On iOS, wrapping content in aSingleChildScrollViewis usually the better fix.
Hot Reload Is Genuinely Transformative
Coming from native Android/iOS development, Flutter’s hot reload is not a gimmick — it changes how you build UI. Being able to iterate on layouts and see results in under a second fundamentally shifts your workflow from “write → build → test” to something much closer to visual design tooling.
What I’d Do Differently
- Define the data model before writing a single widget.
- Use
flutter_genfor type-safe asset references from day one. - Write widget tests earlier — they’re far cheaper to write during development than retroactively.
Overall, Flutter remains my go-to for cross-platform mobile. The DX is excellent, the community has matured enormously, and Dart is an underrated language.