Mobile App Development

Finishing the React Native New Architecture migration ahead of the deprecation deadline

APP

React Native's New Architecture has been the recommended default for a while now, but a couple of our older client apps had put off the migration, partly due to competing priorities and partly because the apps in question were stable enough under the old architecture that migrating felt like effort without an obvious near-term payoff. With the legacy architecture's deprecation deadline approaching this year and official support for it being fully removed, we finally finished the remaining migrations rather than continuing to defer them.

The apps that had already modernized their native module usage over the years migrated with minimal friction. Those apps had, mostly incidentally, kept their native module dependencies reasonably current and avoided some of the deepest legacy patterns that make a New Architecture migration painful, direct assumptions about the old bridge's synchronous behavior, custom native modules written years ago against APIs that had since evolved. For those apps, the migration was close to mechanical: update dependencies, run the provided migration tooling, fix a small number of flagged incompatibilities, and verify behavior against the existing test suite.

The one app still carrying older, less-maintained native dependencies took real extra effort, a reminder that deferred migrations tend to get more expensive, not less, the longer they wait. Several of that app's native modules hadn't been actively maintained by their original authors in years, meaning there was no upstream New Architecture-compatible version to simply upgrade to. We ended up forking two smaller native modules ourselves to port them forward, which is exactly the kind of unplanned maintenance burden that deferred technical debt tends to eventually generate, and which cost meaningfully more engineering time than if the app had migrated a year or two earlier alongside its peers.

We also used the mandatory nature of this migration as an opportunity to audit each app's native dependency list more broadly, not just for New Architecture compatibility but for whether each dependency was still worth carrying at all. A couple of native modules turned out to be handling functionality that had since become available through more actively maintained alternatives, or in one case, through a capability that had been added to React Native's own core since the dependency was first introduced. Removing those unnecessary dependencies as part of the same migration effort was more efficient than treating it as a separate future cleanup project nobody would prioritize on its own.

Testing coverage mattered more during this migration than it usually does for a typical feature change, since the New Architecture's different underlying behavior around native module communication meant that even functionally correct code could behave subtly differently under load or in specific timing-sensitive scenarios. We leaned heavily on each app's existing automated test suite to catch regressions, and the apps with thinner test coverage going in required correspondingly more manual verification effort to reach the same confidence level before shipping.

The broader lesson we're carrying forward: a deprecation deadline that feels comfortably far away is exactly the kind of deadline that's easiest to under-prioritize until it isn't far away anymore. We're treating the next similarly telegraphed platform deprecation with more urgency specifically because of how much more expensive this one became for the app we let slide the longest.

← Back to the journal

Have a project in mind?
Let’s talk.

Tell us where you are and where you want to go. We'll map the fastest route between the two.

Currently accepting new clients