I had apps on Google Play and every year I had to upgrade libs, recompile and loose and afternoon (or two) to not win anything, just churn for the sake of churn.
Compare this to plain HTML, CSS & vanilla JS. You can deploy a webapp today and if you are not using any beta JS Chrome API you will be able to use that site in 10 years without touching a line.
Oh yeah there is nothing "better" than needing to upgrade apps a few weeks before Google Play stops accepting updates because no one thought about it or it gets postponed to the "next sprint". Google is also very bad at communicating about these changes - for example, apps now need to support 16 KB page sizes or they will stop accepting updates on 1st November but the only warning I got about this was the one on 1st September (I'm sure they talked about this sometimes in the past in some blog posts but it's impossible to read and memorize everything). But they will send an email for every little tax-related change happening in some remote island even when you don't have any paid apps! Don't forget updating React Native and all dependencies, too (there will be a lot because RN has literally no batteries included) and you will waste weeks with this because things WILL break and you WILL have to replace some dependencies. Don't get me started on Xcode and iOS.
I built an app for micro-journaling [0] in 2013. I think the iOS version stopped working in 2016, the Android version maybe a year or two after (I switched to iPhone so don't know for sure).
The interactive demo site I built in JS?
Still works exactly the same.
And I tried to make the apps as backwards compatible as possible.
Maybe AI could help make OS upgrade maintenance easier?
Unfortunely using plain HTML, CSS & vanilla JS feels like being a hipster in the age of using SPA or WebAssembly frameworks for displaying static text.
The more relevant comparison is ASP.NET where maintenance is only required to keep up with changing internet standards such as httpOnly cookies or whatever.
The problem with relying on these high-level frameworks, or heavy frameworks of any kind, is that one day they will change their entire approach to how things should be implemented, and then you have a giant pile of legacy on your hands.
I learned that lesson the hard way with ExtJS 3 => 4, and now my wife claims I have commitment issues.
They are close to finally stabilizing the API (as much is possible given underlying platform stability). New Architecture has been in the works for 8 years. It’s such a massive upgrade over legacy architecture. Migrating our app to new architecture was not that hard tbh.
Ooh, I felt this one. I went through porting a webdav browser widget from ExtJS 2.1 -> 3 and then 3 -> 4. It was a nightmare. Does ExtJS still not html encode replacement values in it's templates by default?
I have a lot of respect for the work the React Native folks do but at the same time the constant reinvention just highlights an inherent weakness in any framework like this: you don’t control the platform, so you’re always always at least one step behind.
Sometimes that tradeoff is worth the cost but other times (particularly in the era of Swift and SwiftUI having replaced Objective C and UIKit) you’ll be better off just biting the bullet and learning a little native code. As a JS developer I found Swift to be a delight.
This used to be the case when the platforms were much younger and new features were introduced every year. But I would say it’s mostly stabilized now. React native had day 1 support for Liquid Glass and new AI APIs introduced on iOS 26.
> Sometimes that tradeoff is worth the cost but other times (particularly in the era of Swift and SwiftUI having replaced Objective C and UIKit) you’ll be better off just biting the bullet and learning a little native code. As a JS developer I found Swift to be a delight.
But then you have double the work, in double the languages/frameworks for the two platforms.
For a real world datapoint - my team at a FAANG invested heavily into RN over the course of years, the promoters kept touting the "only write code once!" line, and after years and years of effort in the end we managed to share only ~10% of code for any given new feature. For any given RN feature we also had to write so many APIs/hooks/setup in native code to support it that the 10% code share didn't even save us any time.
In fact, we were prevented from doing a lot of stuff that we wanted to do, because RN either A) didn't support it (because iOS didn't have a similar concept), or B) we were gated on upgrading / using something because it depended on doing a massive RN version upgrade, which nobody wanted to schedule the time for. So I'd argue it was a net negative to productivity overall.
I could continue ranting and raving about this for many paragraphs but I'll limit it there. Not a fan.
It’s not really double, something closer to 1.25x. The bulk of the work is on whatever platform you first implemented the UI on, because that’s where rubber hits the road and you run into things like assumptions the designer made breaking. On the second platform all that’s already done and you just need to replicate.
Besides that, in your typical CRUD app the UI really shouldn’t be the hard part anyway.
Additionally, you’re going to have to deal with per-platform bugs which require you to dig in to the native side to fix even if you go all in on RN or Flutter or whatever the cool thing is this month, and that’s in addition to the bugs with the framework. Finally, major system updates tend to be much more of an ordeal with these frameworks where (for example) mature iOS apps can easily go years without major changes.
There’s also things like https://skip.tools/ which translates your iOS SwiftUI app into native Android Jetpack Compose on the fly.
Double the code, but not necessarily double the work. And look at this blog post: these "write once" solutions often have the surprise of a bunch of extra work you weren't expecting.
Perhaps it's buried in the article somewhere but I think it should highlight in the introduction what business problems were solved or improved, and what the original architecture was; essentially why this major migration was undertaken.
Without knowing the answer, Shopify in general prioritizes staying on the newest version of basically everything. They deploy rails and ruby from main branch into production roughly weekly, for example. So it may just be because its current version.
Can’t speak for shopify but as someone who helps maintain a fairly large react native app there is not really the option to stay on the old versions of things, react native only supports 2 major versions back, and downstream react native dependencies tend to do the same. If you don’t upgrade you are likely to find bugs when new OS versions come out that are gonna make your app close to unusable. There are benefits to the new architecture, better performance is the big one.
One of the biggest arguments against using cross-platform frameworks like React Native comes from the people who use it the most. I can’t help but read articles like this and think that it’s so much unnecessary toil. It took them years to migrate to React Native, and now they have to deal with all this crap.
Great write up. Really appreciate the work from the teams at Shopify, Expo, and countless OSS maintainers pushing the ecosystem forward. Looks like the coast is mostly clear to upgrade to the new architecture, but as a solo dev who only just made it to Expo 52 / Xcode 16, I can’t say I’m excited. With RN/Expo it often feels like a race to build features before the bottom drops out and you’re forced into another round of foundational upgrades just to keep the app building. Even with good migration tools and guides, any non-trivial app will likely hit unique challenges. I don’t think that’s on Expo or Facebook - it’s just the reality of mobile development and reflective of the way Apple and Google shape the ecosystem. Imho mobile platform churn is much worse than developing for web, and working on a mobile app makes me appreciate the web more every day.
With the New Architecture & Expo, react native is in a great state right now and is gaining momentum. We've been able to onboard a lot of web devs onto working on our new Expo universal app at my employer and only a small subset of us need to be react-native experts. We provide a component library & other platform tools to help a bunch of web devs ship an app that works on iOS, android, and web.
Over the air javascript updates are such a massive advantage over fully native apps, and expo-router now has server-driven UI via react server components.
I had apps on Google Play and every year I had to upgrade libs, recompile and loose and afternoon (or two) to not win anything, just churn for the sake of churn.
Compare this to plain HTML, CSS & vanilla JS. You can deploy a webapp today and if you are not using any beta JS Chrome API you will be able to use that site in 10 years without touching a line.
Modern windows won't even play crysis without a binary patch.
My old uni android apps still work on android last i checked. With a recompilation my ios apps work on ios too.
However, with absolutely zero work, ALL of my web stuff across all time works just like it used to even the angular 1 stuff.
It is why i love web so much. It is the ultimate distribution platform with so little needless churn.
I do not agree on this statement at all.
I built an app for micro-journaling [0] in 2013. I think the iOS version stopped working in 2016, the Android version maybe a year or two after (I switched to iPhone so don't know for sure).
The interactive demo site I built in JS?
Still works exactly the same.
And I tried to make the apps as backwards compatible as possible.
Maybe AI could help make OS upgrade maintenance easier?
[0]: www.ifeelio.com
FTFY (but seriously, why do so many sites do that?!?)
Server rendered HTML should be the default.
Dead Comment
I learned that lesson the hard way with ExtJS 3 => 4, and now my wife claims I have commitment issues.
I still feel anger hearing its name the better part of a decade later.
The difference is only in the velocity of changes/updates.
Sometimes that tradeoff is worth the cost but other times (particularly in the era of Swift and SwiftUI having replaced Objective C and UIKit) you’ll be better off just biting the bullet and learning a little native code. As a JS developer I found Swift to be a delight.
But then you have double the work, in double the languages/frameworks for the two platforms.
In fact, we were prevented from doing a lot of stuff that we wanted to do, because RN either A) didn't support it (because iOS didn't have a similar concept), or B) we were gated on upgrading / using something because it depended on doing a massive RN version upgrade, which nobody wanted to schedule the time for. So I'd argue it was a net negative to productivity overall.
I could continue ranting and raving about this for many paragraphs but I'll limit it there. Not a fan.
Besides that, in your typical CRUD app the UI really shouldn’t be the hard part anyway.
Additionally, you’re going to have to deal with per-platform bugs which require you to dig in to the native side to fix even if you go all in on RN or Flutter or whatever the cool thing is this month, and that’s in addition to the bugs with the framework. Finally, major system updates tend to be much more of an ordeal with these frameworks where (for example) mature iOS apps can easily go years without major changes.
There’s also things like https://skip.tools/ which translates your iOS SwiftUI app into native Android Jetpack Compose on the fly.
All in all a lot less trouble than it might seem.
I would have expected Tobi to open cursor and tell it to "migrate."
Over the air javascript updates are such a massive advantage over fully native apps, and expo-router now has server-driven UI via react server components.