Is it worth migrating from React Native to Kotlin and Swift now that we have AI?
Learn when migrating from React Native to Kotlin and Swift with AI makes sense, which costs remain, and how to test the decision with less risk.
AI can make code translation cheaper, but it does not necessarily make operating two platforms cheaper.
For a long time, a complete mobile rewrite seemed reserved for teams with substantial time, budget, and native expertise. Converting screens, state, navigation, integrations, and tests for Android and iOS required a large investment before the product saw any benefit.
Coding agents changed part of that equation. They can now inventory a React Native codebase, map dependencies, and generate initial Kotlin, Swift, Jetpack Compose, and SwiftUI versions much faster. That makes a demo more accessible, but it also creates the risk of confusing a rendered screen with a completed migration.
The short answer: it depends on the problem the migration solves
I would not migrate from React Native to Kotlin and Swift simply because code generation became faster. I would consider it when a relevant, measured problem remained after evaluating smaller alternatives: updating the codebase, reviewing libraries, improving the internal architecture, writing a native module, or replacing only one critical flow.
- Which concrete problem are we trying to solve?
- How will we demonstrate that the new version is better?
- Who will review and maintain Kotlin and Swift next year?
- How much will the coexistence period cost?
- What is the way back if the pilot does not confirm the hypothesis?
Without reasonably clear answers, AI availability is an argument for experimentation, not for migration.
What AI actually changes
AI mainly reduces the marginal cost of producing and analyzing code. It can inventory screens, explain unfamiliar areas, generate scaffolding, translate simple models, suggest tests, compare implementations, and document decisions. That gain can turn an expensive hypothesis into a viable prototype.
But it does not determine correct behavior on its own. It does not automatically know every product decision that became implicit over the years, and it does not take responsibility for lifecycle, battery consumption, concurrency, permissions, accessibility, app-store release, or device-specific failures.
There is also a difference between generating tests and having an independent specification. If an agent misinterprets a rule, it can write both the implementation and the test with the same error. DORA’s report on generative AI reinforces the caution: improving parts of the process does not automatically improve delivery performance; small batches and robust tests still matter.
Mobile migration is not component translation
- Navigation, deep links, and state restoration.
- Authentication, secure storage, and offline behavior.
- Notifications, background tasks, analytics, and crash reporting.
- Camera, location, Bluetooth, permissions, and OS-version differences.
- Accessibility, internationalization, signing, and release.
- API contracts, local persistence, and low-memory lifecycles.
A syntactically elegant translation can remove the exact exception that kept the product working. Before converting files, I would record behavior and contracts: which outcomes must remain true and which limitations the migration is intended to remove.
Before leaving React Native, revisit the hypothesis
React Native is not static. The New Architecture changed native modules, rendering, and communication with the platform. The official documentation also supports platform-specific code, native modules, and coexistence between React Native surfaces and native apps. This does not guarantee that an upgrade solves everything; it means diagnoses such as `React Native is slow` or `we need native capabilities` are too broad to justify a rewrite.
- Is the bottleneck in the framework, application code, or a library?
- Does the codebase use a current version and architecture?
- Does the problem happen on both platforms, and was it measured on real devices?
- Would one native component or module solve the critical issue?
- Is the upgrade cost structural or caused by specific dependencies?
Four paths, not only two
1. Keep and evolve React Native
This makes sense when the app delivers the expected experience, sharing reduces real cost, and current problems can be solved in the existing codebase. It can include an upgrade, gradual adoption of the New Architecture, dependency review, better observability, and domain separation.
2. Add native modules, components, or flows
When the issue is concentrated in camera, maps, media, background work, sensors, or animation, a bounded native solution can deliver the benefit without duplicating the entire app. The cost is maintaining a clear boundary between environments and expertise on both sides.
3. Migrate gradually by flow
The team selects a bounded journey and reimplements it end to end in Kotlin and Swift, with its own tests, telemetry, rollout, and rollback. The result determines whether migration continues, changes direction, or stops. This is the option closest to the Strangler Fig pattern.
4. Do a complete rewrite
This may be appropriate when limitations are systemic, the current architecture prevents important changes, and the organization accepts the investment and risk of a broad cutover. AI reduces part of the implementation effort, but it does not remove the distance between `almost done` and `safe to replace production`.
When migration can make sense
- There is a relevant, reproducible, and measured bottleneck.
- The problem remains after reasonable improvements to the React Native codebase.
- The product depends deeply on platform-specific APIs or behavior.
- The shared layer requires enough exceptions that it no longer simplifies the work.
- The team has native expertise or a sustainable plan to develop it.
- Tests, telemetry, rollout, and rollback exist to compare versions.
- The organization accepts coexistence costs and a temporary reduction in delivery speed.
When it probably does not make sense
- The main motivation is the novelty of an agent or language.
- A quick demo was treated as a production estimate.
- There is no baseline for the current application.
- The team cannot review Kotlin and Swift in depth.
- Tests cannot determine whether behavior was preserved.
- Full parity is required, but the team cannot keep implementations synchronized.
- Post-launch cost has not been discussed.
If nobody can explain why the generated code is correct, production speed turns into technical debt in two languages.
Total cost appears at three moments
1. Construction
Mapping the app, defining architectures, generating and reviewing code, recreating tests, instrumenting observability, documenting decisions, and training people. This is where AI tends to produce its most visible gain.
2. Transition
Keeping React Native while native versions mature, fixing issues in more than one place, synchronizing features, temporarily duplicating pipelines and telemetry, migrating deep links and authentication, and reducing capacity for new features.
3. Recurring operations
Two toolchains, two dependency ecosystems, separate builds and releases, specialized review, app-store changes, security, observability, compatibility, onboarding, and coordination of parity or intentional divergence.
1total cost = construction + transition + recurring operations + opportunity + residual riskParity, testing, and team architecture
Parity does not need to mean copying every pixel. I would separate mandatory shared behavior, deliberately platform-specific experience, and temporary migration differences. This avoids reproducing irrelevant details while preventing regressions from being labeled native choices.
In `Working Effectively with Legacy Code`, Michael Feathers shows the importance of creating safety before aggressively changing a codebase. For a mobile migration, that includes characterization tests, API contracts, critical flows, accessibility, performance, and scenarios involving poor networks, suspension, and low memory. This coverage should begin before conversion.
`Team Topologies`, by Matthew Skelton and Manuel Pais, helps include cognitive load in the decision. AI can reduce mechanical work, but it can also increase review load if it generates more changes than the team can understand. Two platforms require ownership, distributed knowledge, and the ability to respond to incidents in both ecosystems.
The pilot I would run before migrating
Imagine an app with a media capture, editing, and upload flow that has reproducible failures, high memory usage, and differences that are difficult to handle across Android and iOS. I would choose this flow because it contains the problem that motivated the discussion, not because it is the easiest part to demo.
- Measure the current version: completion, crashes, time, memory, resume behavior, accessibility, and maintenance cost.
- Test the smallest alternative: an upgrade, a better library, or a native module.
- Build bounded native implementations with contracts and expert review.
- Release with controls, comparable telemetry, and a previously tested rollback.
- Use evidence to decide whether to stay, keep the module, continue by flows, or broaden the migration.
A pilot that recommends not migrating was not wasted. It bought knowledge and avoided a larger bet.
What the books help us see
- `Building Evolutionary Architectures`: incremental change and fitness functions make important characteristics verifiable during evolution.
- `Working Effectively with Legacy Code`: characterization tests and seams create safety for changing an unfamiliar codebase.
- `Software Architecture: The Hard Parts`: there is no winner outside context; the benefits of one alternative are often the costs of another.
- `Accelerate` and DORA: local productivity is not enough if larger changes increase review effort, instability, and recovery time.
- `Team Topologies`: architecture must fit the team’s cognitive capacity and responsibility boundaries.
- `Strangler Fig`: replacing capabilities gradually reduces the risk of a single cutover.
Checklist before deciding
- Which product, architecture, or operations problem are we solving?
- Is there a reproducible baseline?
- Is the issue in React Native, the application, or a dependency?
- Were upgrades, optimization, or a native module evaluated?
- Which behaviors must remain equivalent?
- Which Android and iOS differences will be intentional?
- Can the team review and maintain Kotlin and Swift?
- How much will coexistence cost?
- Which metrics define success and a stop condition?
- Can the pilot be released and reversed safely?
- How will AI be used in small, reviewable batches?
- Who will own the code after generation?
Conclusion
AI made it cheaper to ask `what if we migrated?` It helps map the codebase, create prototypes, and execute mechanical parts of the transition. But a product does not end when code is generated: it must be reviewed, tested, released, observed, fixed, and evolved.
That is why I would not use AI as justification for a rewrite. I would use AI to make the decision cheaper to test. If a small, measured, reversible flow demonstrates enough benefit, migration can move forward with evidence. If it does not, staying on React Native—perhaps with focused native integrations—remains a valid technical decision.
The question is not whether AI can write Kotlin and Swift. It is whether the new architecture solves an important problem at a cost the team can sustain.
