BLOG · 15 SEPT 2026 · 6 MIN READ

Ionic to React Native migration: what we learned maintaining an app with hundreds of thousands of users

Lessons from maintaining an Ionic app with hundreds of thousands of users while building its React Native successor: parity, auth, push and rollout.

React NativeIonicMobile apps

Rewriting a mobile app is easy to start and hard to finish. Rewriting one that hundreds of thousands of people rely on, while keeping the current version healthy, is a different discipline altogether. We maintained Rocket Lawyer's legal advice app, built with Ionic and used worldwide, while developing its new React Native successor. This article is not a case study with numbers. It is the set of practical lessons that matter in any migration of this kind.

We have also built hybrid apps for a long time: the Ionic and Angular mobile app for Asora, and a hybrid app with SIP.js and WebRTC calling for CloudTalk. So this is not a "hybrid is bad" story. Ionic is a good technology. Migration is a business decision that has to justify its cost.

Decide why you are migrating

Before any code, write down the reasons. Common legitimate ones:

  • Interactions that need to feel fully native: gestures, lists with thousands of items, complex animations.
  • Deeper integration with platform APIs, background tasks or native SDKs.
  • Performance on lower-end Android devices.
  • A company-wide move to React and TypeScript, making hiring and code sharing easier.

Weak reasons include "React Native is more modern" or "the old code is messy". Messy code can be refactored for far less than the cost of a rewrite. The reasons matter because they define what "done" means and which screens deserve native polish first.

It also helps to be honest about the cost. For a period of time you are paying for two apps: two codebases, two sets of store listings to keep compliant, two regression passes and two sets of bugs. Product work slows down, because every new feature either waits for the new app or gets built twice. Put that period on the roadmap explicitly and agree with stakeholders on how long it is allowed to last. A migration without an end date tends to drift, and a drifting migration is the worst outcome: the old app stops improving, and the new one never quite ships.

Run two apps in parallel, deliberately

The hardest part of a migration is not the new app. It is keeping the old one alive without starving it.

Protect the legacy app

Users do not care that a new version is coming. Security updates, OS compatibility fixes, SDK upgrades demanded by store policies and urgent bug fixes still have to ship. We recommend:

  • A dedicated maintenance lane for the old app with clear ownership, so it is never "whoever has time".
  • A feature freeze policy: only critical or revenue-relevant features land in the old app, and each one is added to the parity list for the new one.
  • Store policy tracking: target SDK level requirements and privacy declarations have deadlines, and missing one can block releases of the app you are about to replace.

Build a parity matrix

Feature parity is a list, not a feeling. Keep a matrix that both product and engineering can read:

Area Old app behaviour New app status Notes
Sign in, SSO, biometrics Supported In progress Session migration required
Deep links All marketing and email links Done Tested against link inventory
Push notifications Transactional and marketing Done Token replacement on first launch
Offline documents Cached for signed-in user Not started Storage migration needed
Analytics events Full funnel Partial Event names must match

Include the invisible features: deep link routes, analytics events, accessibility, localisation, error states and edge cases users only hit once a year. Those are what generate support tickets after launch.

Share the API layer, not the UI

The most valuable reuse in an Ionic to React Native migration is below the UI. Ionic apps are written in TypeScript, and so are well structured React Native apps. That makes a lot of logic portable:

  • API clients and request/response types
  • Validation rules and form schemas
  • Business logic, formatting, pricing and date handling
  • Feature flag definitions and remote config keys
  • Design tokens for colours, spacing and typography

Move these into a shared package before or during the rewrite. Keep it free of framework imports so both apps can consume it.

// packages/core/src/api/documents.ts
// Framework-agnostic: used by the Ionic app and the React Native app
export interface DocumentSummary {
  id: string;
  title: string;
  updatedAt: string;
  status: "draft" | "signed" | "archived";
}

export function createDocumentsApi(http: HttpClient) {
  return {
    list: (cursor?: string) =>
      http.get<{ items: DocumentSummary[]; nextCursor?: string }>("/documents", { cursor }),
    get: (id: string) => http.get<DocumentSummary>(`/documents/${id}`),
  };
}

The HttpClient interface is injected, so each app provides its own implementation for auth headers, retries and token refresh. Angular services and React hooks become thin wrappers around the same core.

The migration details that bite

These are the areas where migrations fail quietly, because they only show up on upgraded devices with real history.

Auth and session migration

If the new app ships under the same store listing, users will receive it as an update. They expect to stay signed in. Ionic apps often keep tokens in web storage, a SQLite plugin or a secure storage plugin, while React Native apps typically use the iOS Keychain and Android Keystore through a native module.

Write an explicit one-time migration: read the old location, validate the session with the backend, write to the new secure storage, then delete the old data. Make it idempotent and make failure non-fatal: if migration fails, fall back to a normal sign-in rather than crashing.

Push tokens

Changing the push library or registration flow can produce new device tokens. Register on first launch, send the token with user and device identifiers, and let the backend replace the previous token. Monitor delivery by app version during rollout.

Build an inventory of every link format in use: marketing emails, transactional emails, SMS, web pages, QR codes, partner integrations. Universal links and app links must keep working with the same paths. Automated tests that open each route are cheap insurance.

Offline storage

Cached documents, drafts and preferences live in formats specific to the old stack. Decide per data type: migrate it, re-download it from the server, or accept losing it. Losing a user's unsent draft is the kind of thing that ends up in store reviews.

Analytics parity

If event names and properties change, every funnel and dashboard breaks on launch day, exactly when you need them most to compare old and new. Define the event schema in the shared package and reuse identical names.

Release trains and gradual rollout

A predictable release cadence lowers risk for both apps.

  1. Fixed release trains, for example every two weeks, with a code freeze and a regression pass.
  2. Internal and beta tracks first: TestFlight and Google Play internal or closed testing.
  3. Staged rollout: Google Play supports percentage rollouts, and the App Store supports phased release for automatic updates. Start small and widen as metrics hold.
  4. Kill switches and remote config, so a problematic feature can be disabled without a new store review.
  5. Clear go and no-go metrics: crash-free sessions, sign-in success, key conversion steps and support ticket volume, compared against the old app.
# Example: promote a staged Android rollout with fastlane
fastlane supply --track production --rollout 0.2 --skip_upload_apk true

Plan for store review time in your schedule, and remember that some users never update promptly. The old version will be in the wild for a while, so the backend must support both until usage drops to a level you accept.

What we would tell any team starting now

  • Treat the old app as a product, not a legacy burden.
  • Make parity a written matrix and include invisible features.
  • Extract shared TypeScript logic early.
  • Test migrations on upgraded devices with real data, never only on fresh installs.
  • Roll out gradually with metrics you agreed on before launch.

If you are weighing a migration, our mobile app development team builds both Ionic and React Native apps, and our consulting service can assess whether a rewrite is worth it at all. For web-heavy products, see also our web application work.

Considering a migration or a rescue of an existing app? Contact us and we will send a free project roadmap within 24 hours, written by the senior engineers who would do the work.

Written by

Founder of Crowie and senior full-stack engineer. 15+ years building enterprise systems for banking, aerospace, identity verification and telecom, now shipping production AI agents and MCP servers.

Published 15 Sept 2026 · Updated 15 Sept 2026

FAQ

Questions
answered.

A

Should we migrate from Ionic to React Native at all?

Only if there is a concrete reason. Ionic remains a solid choice for many business apps, especially when a web team maintains them. Migration makes sense when you need smoother native interactions, deeper platform integration, better performance on low-end devices, or a hiring and codebase strategy built around React. If the current app works and the roadmap is modest, improving it is usually cheaper.
B

Can we migrate gradually instead of doing a big-bang rewrite?

Partly. You can reuse the backend, API contracts, business logic written in plain TypeScript, and design tokens. Mixing Ionic web views and React Native screens inside one binary is possible but adds complexity. Most teams build the new app separately, run both in parallel, and roll the new version out gradually through staged store releases to the same app listing.
C

How do we avoid logging users out during the migration?

Plan session migration explicitly. On first launch, the new app reads the refresh token or session from the old app's storage location, validates it with the backend, and writes it to secure native storage. Test this on real upgraded devices, not fresh installs, because fresh installs hide the exact problem you are trying to solve.
D

What happens to push notification tokens when we switch?

Tokens can change when the push library or registration flow changes. The new app should register on first launch, send the new token together with the user and device identifiers, and let the backend replace the old token. Keep the backend able to handle both apps during the transition, and monitor delivery rates by app version.
E

How long should both apps run in parallel?

Until the new app has reached feature parity for the flows that matter, the staged rollout has reached all users, and metrics for crashes, conversion and support tickets are at least as good as before. Keep a hotfix path for the old app throughout, because store review and user update lag mean older versions stay in use for a while.
START

Ready to transform
your idea?

Get a precise development roadmap in 24 hours, completely free. Tell us what you are building and a senior engineer replies, not a sales rep.

Get a free project roadmap in 24h

Response within 24 hours on business days · patrik.kelemen@crowie.io