← Back to blog
FlutterArchitectureBest Practices

Building Production Flutter Apps: Lessons from 40+ Shipped Projects

Engineering Team·

After shipping over 40 Flutter applications to production, we've learned what works — and what doesn't. Here's our playbook.

Architecture

We use a clean architecture pattern with three layers:

  • Data layer — Repositories that abstract data sources (API, local DB, Firebase)
  • Domain layer — Business logic with Riverpod providers
  • Presentation layer — Widgets that consume providers

This separation means you can swap Firebase for a custom backend without touching your UI code.

State Management

We chose Riverpod over Bloc for most projects. The reasons:

  • Simpler boilerplate — no separate Event/State classes
  • Compile-time safety — providers are resolved at compile time
  • Testability — providers can be overridden in tests
  • Code generation — riverpod_generator handles the repetitive parts

CI/CD

Every project ships with a Codemagic pipeline that:

  1. Runs static analysis (dart analyze)
  2. Runs unit and widget tests
  3. Builds iOS and Android binaries
  4. Deploys to TestFlight and Internal Testing
  5. Notifies the team on Slack

Testing

We target 80%+ code coverage with three types of tests:

  • Unit tests — Provider and repository logic
  • Widget tests — Individual widget behavior
  • Integration tests — Full user flows

Key Lessons

  1. Start with CI/CD — The pipeline should be set up before the first feature is built
  2. Design system first — Build your theme, typography, and component library before screens
  3. Error handling is a feature — Every API call needs loading, error, and empty states
  4. Performance from day one — Profile on real devices, not simulators
  5. Automate everything — Code generation, localization, asset management