Skip to content
Innovialabs

Migrating a Native App to Flutter or React Native: Strategies

Advanced4 min

In short

A gradual migration is usually safer: new screens are built in Flutter or React Native inside the native app, one layer owns auth and data, and releases continue as usual; a full rewrite makes sense for small or badly outdated apps.

Two paths and how to choose

There are two main ways to move a native app to a cross-platform stack:

  • Full rewrite: a new app is built from scratch and replaces the old one in a single release.
  • Gradual migration (add-to-app, brownfield): Flutter or React Native is embedded in the existing native app, and screens move over one at a time.
CriterionFull rewriteGradual migration
Risk for current usersHigh: everything changes at onceLower: changes ship in portions
Releases during the workOld app is frozen or maintained in parallelContinue as usual
Architecture complexityLower: one stackHigher: two stacks at once
Build size during transitionNormalLarger: two runtimes
FitsSmall apps, outdated codeLarge, live products

If the app is small and the code is hard to maintain, a rewrite can be simpler. If the product is large, earns money and keeps evolving, going gradually is almost always the wiser choice.

How a gradual migration works

  • Flutter supports add-to-app: a Flutter module is added to the iOS and Android projects, and screens are opened via FlutterViewController and FlutterActivity or FlutterFragment. Pre-warm and reuse the engine, otherwise the first transition to a Flutter screen is noticeably slower.
  • React Native is embedded into the existing app as a set of views that native code opens like ordinary screens.

Order of work:

  1. Define boundaries: which screens and flows move first. Good candidates are new features and isolated sections (profile, settings, catalog).
  2. Set up builds and CI so the module is built together with the native projects.
  3. Define the exchange contract between native and cross-platform parts: navigation, events, data.
  4. Move section by section, deleting native code after each one.
  5. When only a native shell is left, decide whether to switch to a fully cross-platform project.

How to keep releases going

  • Put every migrated screen behind a feature flag and roll it out gradually.
  • Keep the same bundle ID and signing: users should get a normal update, not a new app.
  • Keep the old implementation until the new one proves stable in crash and product metrics.
  • Plan so that each release changes only a limited part of the product.

Sharing auth and data

The most common problem is two parts of the app disagreeing about who the user is.

  • One session owner. Tokens are stored in one place (Keychain, Keystore) and refreshed by one layer. The other part gets the token through a bridge instead of running its own refresh logic.
  • A bridge with an explicit contract. In Flutter, platform channels; the Pigeon generator helps with typed interfaces. In React Native, native modules. Document the contract like an API: methods, types, errors.
  • One source of data. If the native part uses a local database, the cross-platform part reads it through the bridge or a shared API rather than keeping its own copy.
  • Events. Logout, language changes and profile updates must reach both parts.
// Flutter: request a token from the native side
const channel = MethodChannel('app/auth');
final token = await channel.invokeMethod<String>('getAccessToken');

Risks

  • Transition performance between native and cross-platform screens.
  • Larger build size during the transition.
  • Two skill sets needed in the team at the same time.
  • Native dependencies: SDKs without a plugin or module must be wrapped by hand.
  • A stalled migration, where half the app stays on two stacks forever.

When migration is not worth it

  • Native teams work well, and the product's problems are not about technology.
  • The app depends heavily on platform features: advanced camera work, AR, background services, widgets.
  • There are no resources to finish the migration. A half-done migration costs more than either clean option.
  • The reason is fashion rather than measurable goals such as feature velocity, a single team or shared code.

FAQ

Your team and context decide. A strong React web team can reuse its knowledge with React Native. Flutter offers a single rendering engine and predictable UI on both platforms. Both support gradual migration.

We can help with this

If you'd rather get the result than figure it all out yourself — this is what we do every day.

Discuss a project

Read next

Have an idea or a task? Tell us about it

We'll reply within one business day and propose a solution. The consultation is free.