I agree with most of the other comments here, and it sounds like Shopify made sound tradeoffs for their business. I'm sure the people who use Shopify's apps are able to accomplish the tasks they need to.
But as a user of computers and occasional native mobile app developer, hearing "<500ms screen load times" stated as a win is very disappointing. Having your app burn battery for half a second doing absolutely nothing is bad UX. That kind of latency does have a meaningful effect on productivity for a heavy user.
Besides that, having done a serious evaluation of whether to migrate a pair of native apps supported by multi-person engineering teams to RN, I think this is a very level-headed take on how to make such a migration work in practice. If you're going to take this path, this is the way to do it. I just hope that people choose targets closer to 100ms.
When the user clicks a button, we start a server round-trip and fetch the data and do client-side parsing, layout, formatting and rendering and then less than 500ms later, the user can see the result on his/her screen.
With a worst-case ping of 200ms for a round-trip, that leaves about 200ms for DB queries and then 100ms for the GUI rendering, which is roughly what you'd expect.
Since the post is about the benefits of react, I'm sure if requests were involved they would mention it.
Also, even if it was involved, 200ms for round-trip and DB queries is complete bonkers. Most round-trips don't take more than 100ms, and if you're taking 200ms for a DB query on an app with millions of users, you're screwed. Most queries should take max 20-30ms, with some outliers in places where optimization is hard taking up to 80ms.
If you are good those numbers are an order of magnitude off. In truth it is probably mostly auth or something. If you simply avoid json you can radically attack these things fast.
RTT to nearest major metro DC should be up to 20ms (where I am it is less than half that), your DB calls should not be anything like 200ms (and in the event they are you need to show something else first), and 10-20ms is what you should assume for rendering budget of something very big. 60hz means 16ms per frame after all.
No. Just no. There’s an entire generation of devs at this point who are convinced that a DB is something you throw JSON into, use UUIDs for everything, add indices when things are slower than you expected, and then upsize the DB when that doesn’t fix it.
RAM access on modern hardware has a latency of something like 10 nanoseconds. NVMe reads vary based on queue depth and block size, but sub-msec is easily attainable. Even if your disks are actually a SAN, you should still see 1-2 msec. The rest is up to the DB.
All that to say, a small point query on a well-designed schema should easily execute in sub-msec times if the pages are in the DB’s buffer pool. Even one with a small number of joins shouldn’t take more than 1-2 msec. If this is not the case for you, your schema, query, or DB parameters are sub-optimal, or you’re doing some kind of large aggregation query.
I took a query from 70 to 40 msec today just by rewriting it. Zero additional indexing or tuning, just unrolling several unnecessary nested subqueries, and adding a more selective predicate. I have no doubt that it could get into the single digits if better indexing was applied.
I beg of devs, please take the time to learn SQL, to read EXPLAIN plans, and to measure performance. Don’t accept 200 msec queries as “good enough” because you’re meeting your SLOs. They can be so much faster.
People have gotten used to that, but UI work back to the 1960s has done studies and showed clearly that for many of these operations you get tens of ms before people notice and their attention wanes. The web often doesn't allow for response times as fast as the humans need, which is a good reason to write real apps not web apps. That is also why I use tabs - load a bunch in the background so when I'm ready I can just switch tabs and it is there.
500ms is the 75th percentile speed, so 75% of users are having load times faster than that. For context, Google's synthetic p75 loads emulate a crappy old Android phone on a bad network.
A linked post[0] says their p75 was 1400ms before 2023, yowza.
No. It on a request basis, meaning that one in a four clicks a user does take more than half a second to complete. Slow times for as low percentiles as 75 mean users hit the bad cases very often in practice.
2 seconds to wait for a webpage to load isn’t even that bad. If you take an average user on facebook it is horrendously slow - to someone who knows how fast something can be - but no typical user cares/notices. They just accept it.
Nike’s website is phenomenally quick. But again. Ask anyone if that is what they care about. Nope. It’s the shoes.
Replying to myself for clarification: I did not read their 500ms number as including waiting for a network. It sounded like that's how long it was taking React Native to load local data and draw the screen. If that's not the case, it's a very different story.
> For example, I just recorded myself tapping on a product in the Product list screen and the delay between the pressed state appearing and the first frame of the screen transition animation is more than half a second. The animation itself then takes 300ms which is a generally accepted timeframe for screen animations. But that half second where I'm waiting for the app to respond after I've tapped a given element is painful.
> Having your app burn battery for half a second doing absolutely nothing is bad UX. That kind of latency does have a meaningful effect on productivity for a heavy user.
The implication is that React Native is to blame for this and I'm not sure that's true. What would the ms delay be with pure native? I have plenty of native apps that also have delays from time to time.
It all depends on whether the number includes network roundtrip or not, which they don't state. I read it as not including a network request, i.e. all CPU and local I/O.
Indeed. The games industry uses immediate mode GUIs and people get upset if they achieve less than 60fps. Having everything be this slow is just a huge failure of coordination on behalf of the industry.
(next mini question: why is it seemingly impossible to make an Android app smaller than 60mb? I'm sure it is possible, but almost all the ones I have from the app store are that size)
Can't speak for every app but I've worked on several through the years, a sizeable chunk of all the apps I've worked on were assets. It's possible to hide a lot of it from the app store size if you really wanted to but you'd end up downloading all the assets at some point anyway so there's really no point in putting the extra engineering effort in just to make your app store number look smaller.
This obviously isn't the case for every app and most of the ones I've worked on had a lot of bloat/crap in them as well.
Subjectively, I find the Shop app to be quite nice and speedy. It works well enough that I’d never have guessed it is using any kind of cross platform framework.
It’s easy to get caught up on numbers, but at the end of the day the user experience is all that matters. And I very much doubt that performance is a concern for their users.
Exactly. Tech people almost always go to the "performance wormhole" arguing about ms and how it could be improved 10x - myself included. But working at a startup the past couple of years, I came to the conclusion that it does not matter to the end users at all. If an app is "nice" and "speedy" as you say, that’s enough. Shopify made a good decision and tradeoffs; it works for them, and I would argue it would work for 90% of other companies as well. You don't really need a native app for most purposes; React Native and Flutter are good enough.
It's a cross-platform spiritual successor of WPF and it kicks ass! You get proper separation of models and views, you can separate what controls there are from how they look (themes/styles), you can build the entire thing into a native compiled application with very reasonable speed and memory use.
Assuming the 500ms is mostly delay for fetching data over a socket, unless the code is really broken that should not really be burning battery. <500ms for display of non-trivial network-fetched data is great regardless of whether it's rendered by react native or is a fully native app. They would both be I/O-bound on the network primarily, with a small but insignificant compute overhead for RN. If the data needs lots of transformation (though not compute-intensive transformation like calculating hashes or somethign) upon returning that could make a difference, though again I'd be surprised if CPU for RN vs native was all that different.
As an Elixir dev who aims for and routinely achieves <10ms response times, (and sometimes < 1 ms for frequent endpoints that I can hand optimize into a single efficient SQL query, which Ecto makes easy I might add!) I find the response time to be the more egregious part :-D
> Having your app burn battery for half a second doing absolutely nothing is bad UX.
Why are you assuming the app is either burning much battery or even doing more than waiting on current data from the server? For an app that I would assume isn't much use without up-to-date data from the server?
> I just hope that people choose targets closer to 100ms.
Why? If it's about the phone burning battery for 500ms, it probably isn't doing that - it's just waiting for data to arrive. And even when it's rendering, it's probably not burning battery like say Uber (with which you can feel the battery melt in your hands).
But that's not why I am commenting. I am writing because so many commentors are saying that 500ms is bad. Why is 500ms bad, as long as the UI is not freezing or blanking out?
Why not lower expectations, and wait for half a second? Of course, there are apps for which 500ms is unacceptable - but this doesn't seem to be one of them.
I thought the section on the importance of native devs and how they're staffing mobile was really interesting:
"Native devs are crucial
Mobile engineers who specialize in iOS and Android are essential to building great mobile apps. There is no replacing experience and taste that comes from having built many mobile products and deeply understanding conventions and usability. Being able to drop down to the platform layer, write bindings, master build & release, distribution, etc requires native expertise.
They also play a vital role in optimizing app performance across the myriad of device models, ensuring a consistent user experience for all users. Additionally, native expertise is essential for managing React Native version updates, as well as adopting new features, APIs, and tooling changes that accompany new iOS and Android releases. You can't build a good product without these experts.
We invested in training our native mobile developers in React Native through a self-serve course that covered everything they needed to know to ship production-ready code. Additionally, we set up office hours with developers who were already proficient in React Native to provide support through Q&A sessions, pair programming, and code reviews.
We also supplemented our mobile teams with some web developers for their Javascript, Typescript, and React expertise. This ensured we had strong expertise in both native and React Native, and over time, it levelled up the entire team.
Having a good mix of native and web developers is the key to building great mobile apps using React Native in our experience. "
Probably the first "we adopted x" blog post that I can find relatable and spot-on.
I think it's one of the big misconceptions that React Native is _the_ path to get your web devs or even existing code onto mobiles. That's how you get the criticism that RN builds bad, mouldy apps.
Between our clients that have had this issue with quality and shops in the same space as us that haven't (one who boasts a review on one of their apps being "an example on how to build a proper fully native app"), having a good portion of native devs on the team is a big differentiator. Unfortunately this means a RN Team isn't as cheap as some hope.
I was listening to a podcast around 2017 (?) with AirBnb (?) devs when they were using RN and I remember they said “RN is a tool for mobile devs to not write the same app twice, not a shortcut for web devs to not learn native”.
As someone who works with React Native this is definitely true. Imagine a venn diagram:
Full Navive: 2 very big bubbles
React Native: 2 small bubbles and one big bubble
It doesn't happen very often but it can be quite annoying to implement features that need native controls on both platforms. In my case I only know native android (no ios) so when implementing native things I need to bring in an ios native dev and agree on the communication API and any platform-specific edge case before implementing stuff.
It is a lot easier when I can do it all by myself and it is even harder for team members who have no native experience at all.
Blazing fast is a bold claim. I use this app nearly every day on a brand new Pixel 9 Pro and, while much improved from a few years ago, it is far from "blazing fast".
For example, I just recorded myself tapping on a product in the Product list screen and the delay between the pressed state appearing and the first frame of the screen transition animation is more than half a second. The animation itself then takes 300ms which is a generally accepted timeframe for screen animations. But that half second where I'm waiting for the app to respond after I've tapped a given element is painful. UX studies indicate 0.1s as a number where an application no longer feels instantaneous. (https://www.nngroup.com/articles/response-times-3-important-...)
Contrast this against something like the Slack app where the screen is navigating even before the pressed animation has appeared. Or for an app with probably not as much engineering focus, Fastmail, which begins the screen transition within 100ms of the pressed animation state appearance.
Developing for Apple can be a PITA with their strict background processing rules, apps just terminate/stop working unless they fall under a special case. I get it but yeah.
edit: by terminate I don't mean crash, it just stops code execution an example is an active socket connection getting disconnected unless it's doing something like streaming audio
I'm surprised that there was no mention of Expo. In the past, I would say bare-metal is better than Expo-managed React Native projects because of the limitations when it came to native modules. Fast forward to today, and anything you can do in a bare metal RN app can be done with Expo.
The biggest game-changer recently is Expo's Continuous Native Generation[0]. You can configure all of your native modules and ios/android files with a simple config file (which has its limits, whereby you'll need to write an Expo Config Plugin[1]). You will no longer commit the ios/android native code to your repository, and instead let it be procedurally built.
This resolved a lot of environment issues developers would often run into, and greatly simplified onboarding new devs. You can build your iOS/Android apps through the CI with ease. And you'll no longer be afraid of upgrading React Native, as Expo will handle all of the breaking changes in the native code for you.
My guess is that Shopify started with bare metal React Native apps (which I would have done the same 5 years ago), and now migrating back to Expo-managed projects is nontrivial. At my work we only manage one app, and it was well worth migrating back.
React Native renders actual native widgets to the screen, so for example on iOS you would write to cross-platform abstractions but you’d still get real UIKit components on the screen.
Flutter draws its own components that can look superficially like the target platform (or not, it’s up to the developer) in a manner closer to a game engine. HN seems to love Flutter and apparently the developer experience is excellent, but as a user I find Flutter apps to be in general a poor experience. They rarely look or act quite right (assuming the developers even try; I’ve used a number that look like someone has transplanted an Android app onto iOS).
My thought is that Expo prioritises web compatibility too much to the point that it leans into conventions with things like navigation that are web-oriented and these contribute towards an app not feeling like a native app.
You'd hope they benchmarked the old native iOS app and the RN app.
Since the blog post doesn't mention previous native-only perf, I'd assume they didn't compare or the RN version isn't close to native-only perf (leaning heavily towards the second reason).
Looking at a previous blog post, the first hunch seems to be correct - the second may also be true.
I hope they benchmark their load-screen time with every release/CD to stay on top of any regressions, otherwise, there'll be more mad scrambles when the perf debt piles up too high.
Right after that, they have three links (one blog post, two videos) to explanations of how they optimized screen load speed that can answer that question.
It's a mix of layout stuff (like using lazy list views to avoid below the fold rendering) and network fetches (they talk about using better caching).
That was my initial thought as well. Anyone know what native screen loads typically are? I’m sure it varies wildly between apps, but 500ms seems like it would be on the slower end of a “fast” app.
It really depends on what a "screen load" means exactly. If its just rendering the screen from some client-side data then I would expect something <16ms. To support 120fps displays, it would need to be <8ms.
If a "screen load" includes making a network request to fetch data, then this is a very weird metric to include in a post about React Native. Most of that time budget should just be waiting for the request to complete. Just as before, it should take <16ms to render the screen once the data arrives.
For typical apps, the four variables here are backend latency, network latency, client-side deserialization, and client GUI rendering. (Less commonly, apps which have complex client-side state will also spend time reconciling server and client state.)
Keeping UI rendering under 16ms is the gold standard for native apps. That leaves only deserialization as the other target which the mobile developer can optimize. However, the typical solution there involves convincing the backend to ship a different format (i.e. switching from JSON to binary PList or to SQLite DB file).
For reference, our app is 100% in Jetpack Compose, our screen rendering for both cold and warm are in the average of ~460-480ms. App start is around ~480ms.
This strikes me as curiously defensive, in that Canadian way of praising things that are obviously problematic to draw attention to them.
The wider noise around React Native is seemingly that it works, especially while iterating on things, but it makes the final 20% of work much harder than it already was. As one person put it to me recently “with RN you just have to face the fact you won’t be winning any design awards”.
What really amazes me is how far React Native and web React have separated, to the point using the web one is a complete non event.
I just kinda looked around the Shopify app to get a feel for it. There are a few frameworks that tap into native view switching (transitioning between pages and tabs), which creates most of the native feeling (along with native view components like lists/menus/switches).
I don’t know why the quality of the app feels cheap, but it just feels so (the web views load in with zero ease, they just jank onto the screen. So while you have native screen transitioning, you still have this low quality feeling of a bad nypost article shitting out an ad popup on you. Hard to explain, but that’s my my general feeling).
Regardless, while not impressive, it’s in this non-impressiveness that informs my unwillingness to invest into native or something like Flutter. These apps are too simple to go through the hoops.
Shopify RN app is a good example of a mundane non-sexy tech decision.
Overall nothing beats CSS and JavaScript for UI, but even in 2025 we cannot reliably push 60fps.
I disagree with you on a few specifics, but I think the more general question does become what should the Shopify app be like? Non sexy is, as you say, probably the right call.
For mobile apps generally I cannot recall the last time I was actually impressed by one. The reverse is often true, such as with Sonos. Individual features (again Sonos, the calibration it can do) can be neat but experiences as a whole have gone off a cliff, React Native or not.
Glad they spent some times discussing the downsides. I’m 4 months in to a Hotwire Native replacement for an unmaintained React Native app. The differences are stark and I could definitely see myself picking up Hotwire again for another project if given the same constraints, but I’ve had good experiences with React Native in the past too. Ultimately though I just do not like all the work that has to go into maintaining a large scale React codebase.
Theres a constant churn of a bunch of dependencies. Devs add minuscule libraries all the time. And I think some of the best React libraries have been abandoned, which is kinda sad, but nice from a maintenance perspective.
React very much feels like programming using only side-effects and that’s not really a fun experience IMHO. Performance issues are also somewhat difficult to spot in review and not very elegant to solve.
It’s been a few years since I’ve used React Native so maybe things are better now?
We maintain a few number of projects for clients - the apps are feature complete and will not change much in the next years. The goal here is to spend not much money on the apps but to keep them functional in the appstore.
RN is somewhat cheaper up fron than native development or say flutter. Unfortunately, maintenance cost is high and difficult to predict.
Why?
Appstores are adding new requirements and increase API-level all the time. Support for that is often baked into new RN versions. Unfortunately, new RN versions often break things, which break libraries in turn. So you need to upgrade this morass and if you are unlucky, you need to redevelop huge swaths of your app because the lib now is deprecated /works differently / will never be updated to the new RN version.
I was glad to see the discussion as well but it feels like the downsides were also very understated. Working on an RN app as a native dev requires a lot of cross-domain knowledge that isn't typical for a native dev.
Great to see Hotwire Native here! I was asking myself would it be easier for Shopify to steer back more towards Rails ecosystem technologies. They went React / JavaScript full-throttle. JavaScript ecosystem seems so immature, and changing constantly with a huge maintenance burden. Rails feels really stable and Hotwire, although it's changing, feels stable. Stimulus was announced in 2018 I believe and they didn't have a single paradigm shift comparable to React's hooks, server components, etc.
So basically, as long as you are large enough to have direct contact with the upstream team, have a separate team to manage React Native itself, and have two separate teams for iOS and Android to manage stuff that needs native access, you are good.
But as a user of computers and occasional native mobile app developer, hearing "<500ms screen load times" stated as a win is very disappointing. Having your app burn battery for half a second doing absolutely nothing is bad UX. That kind of latency does have a meaningful effect on productivity for a heavy user.
Besides that, having done a serious evaluation of whether to migrate a pair of native apps supported by multi-person engineering teams to RN, I think this is a very level-headed take on how to make such a migration work in practice. If you're going to take this path, this is the way to do it. I just hope that people choose targets closer to 100ms.
When the user clicks a button, we start a server round-trip and fetch the data and do client-side parsing, layout, formatting and rendering and then less than 500ms later, the user can see the result on his/her screen.
With a worst-case ping of 200ms for a round-trip, that leaves about 200ms for DB queries and then 100ms for the GUI rendering, which is roughly what you'd expect.
Also, even if it was involved, 200ms for round-trip and DB queries is complete bonkers. Most round-trips don't take more than 100ms, and if you're taking 200ms for a DB query on an app with millions of users, you're screwed. Most queries should take max 20-30ms, with some outliers in places where optimization is hard taking up to 80ms.
RTT to nearest major metro DC should be up to 20ms (where I am it is less than half that), your DB calls should not be anything like 200ms (and in the event they are you need to show something else first), and 10-20ms is what you should assume for rendering budget of something very big. 60hz means 16ms per frame after all.
No. Just no. There’s an entire generation of devs at this point who are convinced that a DB is something you throw JSON into, use UUIDs for everything, add indices when things are slower than you expected, and then upsize the DB when that doesn’t fix it.
RAM access on modern hardware has a latency of something like 10 nanoseconds. NVMe reads vary based on queue depth and block size, but sub-msec is easily attainable. Even if your disks are actually a SAN, you should still see 1-2 msec. The rest is up to the DB.
All that to say, a small point query on a well-designed schema should easily execute in sub-msec times if the pages are in the DB’s buffer pool. Even one with a small number of joins shouldn’t take more than 1-2 msec. If this is not the case for you, your schema, query, or DB parameters are sub-optimal, or you’re doing some kind of large aggregation query.
I took a query from 70 to 40 msec today just by rewriting it. Zero additional indexing or tuning, just unrolling several unnecessary nested subqueries, and adding a more selective predicate. I have no doubt that it could get into the single digits if better indexing was applied.
I beg of devs, please take the time to learn SQL, to read EXPLAIN plans, and to measure performance. Don’t accept 200 msec queries as “good enough” because you’re meeting your SLOs. They can be so much faster.
200ms round trip is like 10x more than what's reasonably possible.
Same with your other numbers.
A linked post[0] says their p75 was 1400ms before 2023, yowza.
[0] https://shopify.engineering/improving-shopify-app-s-performa...
No. It on a request basis, meaning that one in a four clicks a user does take more than half a second to complete. Slow times for as low percentiles as 75 mean users hit the bad cases very often in practice.
Deleted Comment
Nike’s website is phenomenally quick. But again. Ask anyone if that is what they care about. Nope. It’s the shoes.
From another comment by seemack (https://news.ycombinator.com/item?id=42730348):
> For example, I just recorded myself tapping on a product in the Product list screen and the delay between the pressed state appearing and the first frame of the screen transition animation is more than half a second. The animation itself then takes 300ms which is a generally accepted timeframe for screen animations. But that half second where I'm waiting for the app to respond after I've tapped a given element is painful.
Deleted Comment
The implication is that React Native is to blame for this and I'm not sure that's true. What would the ms delay be with pure native? I have plenty of native apps that also have delays from time to time.
(next mini question: why is it seemingly impossible to make an Android app smaller than 60mb? I'm sure it is possible, but almost all the ones I have from the app store are that size)
This obviously isn't the case for every app and most of the ones I've worked on had a lot of bloat/crap in them as well.
I've just tried whatsapp, notes, gallery, settings and discord out of curiosity, none did and I have a very fast phone.
It’s easy to get caught up on numbers, but at the end of the day the user experience is all that matters. And I very much doubt that performance is a concern for their users.
It's a cross-platform spiritual successor of WPF and it kicks ass! You get proper separation of models and views, you can separate what controls there are from how they look (themes/styles), you can build the entire thing into a native compiled application with very reasonable speed and memory use.
[0] https://avaloniaui.net
As an Elixir dev who aims for and routinely achieves <10ms response times, (and sometimes < 1 ms for frequent endpoints that I can hand optimize into a single efficient SQL query, which Ecto makes easy I might add!) I find the response time to be the more egregious part :-D
Why are you assuming the app is either burning much battery or even doing more than waiting on current data from the server? For an app that I would assume isn't much use without up-to-date data from the server?
Why? If it's about the phone burning battery for 500ms, it probably isn't doing that - it's just waiting for data to arrive. And even when it's rendering, it's probably not burning battery like say Uber (with which you can feel the battery melt in your hands).
But that's not why I am commenting. I am writing because so many commentors are saying that 500ms is bad. Why is 500ms bad, as long as the UI is not freezing or blanking out?
Why not lower expectations, and wait for half a second? Of course, there are apps for which 500ms is unacceptable - but this doesn't seem to be one of them.
"Native devs are crucial
Mobile engineers who specialize in iOS and Android are essential to building great mobile apps. There is no replacing experience and taste that comes from having built many mobile products and deeply understanding conventions and usability. Being able to drop down to the platform layer, write bindings, master build & release, distribution, etc requires native expertise.
They also play a vital role in optimizing app performance across the myriad of device models, ensuring a consistent user experience for all users. Additionally, native expertise is essential for managing React Native version updates, as well as adopting new features, APIs, and tooling changes that accompany new iOS and Android releases. You can't build a good product without these experts.
We invested in training our native mobile developers in React Native through a self-serve course that covered everything they needed to know to ship production-ready code. Additionally, we set up office hours with developers who were already proficient in React Native to provide support through Q&A sessions, pair programming, and code reviews.
We also supplemented our mobile teams with some web developers for their Javascript, Typescript, and React expertise. This ensured we had strong expertise in both native and React Native, and over time, it levelled up the entire team.
Having a good mix of native and web developers is the key to building great mobile apps using React Native in our experience. "
I think it's one of the big misconceptions that React Native is _the_ path to get your web devs or even existing code onto mobiles. That's how you get the criticism that RN builds bad, mouldy apps.
Between our clients that have had this issue with quality and shops in the same space as us that haven't (one who boasts a review on one of their apps being "an example on how to build a proper fully native app"), having a good portion of native devs on the team is a big differentiator. Unfortunately this means a RN Team isn't as cheap as some hope.
Full Navive: 2 very big bubbles
React Native: 2 small bubbles and one big bubble
It doesn't happen very often but it can be quite annoying to implement features that need native controls on both platforms. In my case I only know native android (no ios) so when implementing native things I need to bring in an ios native dev and agree on the communication API and any platform-specific edge case before implementing stuff.
It is a lot easier when I can do it all by myself and it is even harder for team members who have no native experience at all.
Dead Comment
For example, I just recorded myself tapping on a product in the Product list screen and the delay between the pressed state appearing and the first frame of the screen transition animation is more than half a second. The animation itself then takes 300ms which is a generally accepted timeframe for screen animations. But that half second where I'm waiting for the app to respond after I've tapped a given element is painful. UX studies indicate 0.1s as a number where an application no longer feels instantaneous. (https://www.nngroup.com/articles/response-times-3-important-...)
Contrast this against something like the Slack app where the screen is navigating even before the pressed animation has appeared. Or for an app with probably not as much engineering focus, Fastmail, which begins the screen transition within 100ms of the pressed animation state appearance.
Not saying I have the answer, but it is a curiosity
edit: by terminate I don't mean crash, it just stops code execution an example is an active socket connection getting disconnected unless it's doing something like streaming audio
The biggest game-changer recently is Expo's Continuous Native Generation[0]. You can configure all of your native modules and ios/android files with a simple config file (which has its limits, whereby you'll need to write an Expo Config Plugin[1]). You will no longer commit the ios/android native code to your repository, and instead let it be procedurally built.
This resolved a lot of environment issues developers would often run into, and greatly simplified onboarding new devs. You can build your iOS/Android apps through the CI with ease. And you'll no longer be afraid of upgrading React Native, as Expo will handle all of the breaking changes in the native code for you.
My guess is that Shopify started with bare metal React Native apps (which I would have done the same 5 years ago), and now migrating back to Expo-managed projects is nontrivial. At my work we only manage one app, and it was well worth migrating back.
[0] https://docs.expo.dev/workflow/continuous-native-generation/
[1] https://docs.expo.dev/config-plugins/introduction/
Flutter draws its own components that can look superficially like the target platform (or not, it’s up to the developer) in a manner closer to a game engine. HN seems to love Flutter and apparently the developer experience is excellent, but as a user I find Flutter apps to be in general a poor experience. They rarely look or act quite right (assuming the developers even try; I’ve used a number that look like someone has transplanted an Android app onto iOS).
Expo is React Native with some nice things sprinkled on top. I'd go with Expo.
I’m not sure I would consider 0.5 seconds to be blazing fast.
I wish the article went into detail on what these screens do and what a screen load means exactly.
Since the blog post doesn't mention previous native-only perf, I'd assume they didn't compare or the RN version isn't close to native-only perf (leaning heavily towards the second reason).
Looking at a previous blog post, the first hunch seems to be correct - the second may also be true.
From 2024 March, https://shopify.engineering/improving-shopify-app-s-performa... talks about how their RN-ified app was loading screens in 1400ms (P75) and the steps they took to reduce that to 500ms.
I hope they benchmark their load-screen time with every release/CD to stay on top of any regressions, otherwise, there'll be more mad scrambles when the perf debt piles up too high.
It's a mix of layout stuff (like using lazy list views to avoid below the fold rendering) and network fetches (they talk about using better caching).
If a "screen load" includes making a network request to fetch data, then this is a very weird metric to include in a post about React Native. Most of that time budget should just be waiting for the request to complete. Just as before, it should take <16ms to render the screen once the data arrives.
500ms sounds about right for a cold launch but otherwise is pretty poor.
50-100ms for "minor" screen changes and 100-200ms for "major" ones are otherwise reasonable for native screens.
Keeping UI rendering under 16ms is the gold standard for native apps. That leaves only deserialization as the other target which the mobile developer can optimize. However, the typical solution there involves convincing the backend to ship a different format (i.e. switching from JSON to binary PList or to SQLite DB file).
The wider noise around React Native is seemingly that it works, especially while iterating on things, but it makes the final 20% of work much harder than it already was. As one person put it to me recently “with RN you just have to face the fact you won’t be winning any design awards”.
What really amazes me is how far React Native and web React have separated, to the point using the web one is a complete non event.
I don’t know why the quality of the app feels cheap, but it just feels so (the web views load in with zero ease, they just jank onto the screen. So while you have native screen transitioning, you still have this low quality feeling of a bad nypost article shitting out an ad popup on you. Hard to explain, but that’s my my general feeling).
Regardless, while not impressive, it’s in this non-impressiveness that informs my unwillingness to invest into native or something like Flutter. These apps are too simple to go through the hoops.
Shopify RN app is a good example of a mundane non-sexy tech decision.
Overall nothing beats CSS and JavaScript for UI, but even in 2025 we cannot reliably push 60fps.
For mobile apps generally I cannot recall the last time I was actually impressed by one. The reverse is often true, such as with Sonos. Individual features (again Sonos, the calibration it can do) can be neat but experiences as a whole have gone off a cliff, React Native or not.
React very much feels like programming using only side-effects and that’s not really a fun experience IMHO. Performance issues are also somewhat difficult to spot in review and not very elegant to solve.
It’s been a few years since I’ve used React Native so maybe things are better now?