Migrating from FlutterFlow to Flutter: from export to a maintainable codebase
FlutterFlow is fast as long as an app fits the builder. At some point, requirements appear that can only be met there with a lot of custom code, or not at all: an architecture of your own, tests, code reviews in a team, complex state, special native integrations. Then the question is whether to continue the app as a regular Flutter project.
What the export contains
FlutterFlow generates real Flutter code. Depending on the plan, it can be downloaded or pushed to a GitHub repository. An export typically contains:
- a widget and a matching model class for each page,
- the
flutter_flow/folder with theme, helper functions and standard widgets, - a global app state (
FFAppState) based on Provider, - routing based on
go_router, - the connection to the backend, for example Firebase, Supabase or REST APIs,
- custom code from FlutterFlow under
custom_code/.
The code runs, but it’s written for the editor, not for people: lots of generated boilerplate, logic inside widgets, state in many places.
The most important decision up front
The step is practically one-way. Changes to the exported code can’t be brought back into the FlutterFlow editor. If the team keeps working in both worlds after the export, the next export overwrites the manual work. So there needs to be a cut-off date after which development happens in code only.
Migration order
- Freeze and export. The last state from FlutterFlow becomes its own commit with a tag in the repository.
- Establish a build baseline. Pin Flutter and package versions, get
flutter analyzeclean, set up CI, for example with GitHub Actions or Codemagic, and make the iOS and Android builds reproducible. - Secure the critical flows. Before restructuring, write tests for sign-in, core features and payment flows, so that refactorings don’t break anything unnoticed.
- Restructure step by step, don’t rewrite. First theme and design tokens, then the global state, for example moving to Riverpod, then data access and the API layer, and the pages last. After each step, the app stays releasable.
- Keep routes stable. Deep links and push notifications depend on the paths. Changes to them need planning.
- Remove generated ballast. Delete unused pages, helper functions and packages. That makes the app smaller and the code easier to oversee.
A complete rebuild is rarely necessary. It pays off when the app’s functional structure no longer fits, not just its code.
Support
I move FlutterFlow projects into clean Flutter code and get them into the stores. Before we talk about scope and effort, I look at the export, the build pipeline and the store accounts. Get in touch.