I still prefer React Native with Expo over Flutter, mostly for practical reasons:
* Language and hiring: TypeScript has a much larger developer pool. Dart is a solid language, but finding experienced Flutter engineers is harder.
* Platform model: React Native maps much more naturally to native platform concepts. Flutter owns much more of the rendering stack, which is powerful, but also creates another abstraction layer between the app and the platform.
* Performance: Flutter can absolutely be fast, so I would not claim otherwise. My experience, however, is that RN has required less work to get interactions and animations that feel consistently native.
* Ecosystem: RN benefits from the broader React, TypeScript, JavaScript, and native ecosystems. Expo has also improved dramatically and now covers a large part of the usual mobile platform work.
* Platform-specific features: neither framework completely eliminates native code. Things like widgets, Live Activities, Dynamic Island, extensions, NFC, and other platform APIs eventually bring you back to Swift/Kotlin anyway.
* Migration to native: if the long-term destination is Swift and Kotlin, I find RN a better intermediate representation. Its component model and platform integration are closer to native concepts, which also makes the codebase easier for agents to translate incrementally into proper native applications.
That said, these are trade-offs, not claims that Flutter is bad. Flutter has improved a lot, and for teams that want a highly consistent cross-platform UI, its rendering model can be an advantage.
You should try Dart/Flutter again, they've improved a lot.
- Dart. It's richer than JS/TS with stronger type safety, and seems purpose-built for UI. Fewer Dart developers than JS, but I'd argue those JS developers cannot be immediately effective coding React Native (Expo) anyway.
- Emulated components vs. real native components. For multi-platform apps, this is actually desirable. These kinds of apps have their own design system.
- Speed. In my experience, it's negligible, but maybe because I keep using the latest version.
- Ecosystem. Flutter/Dart occasionally introduces "breaking" changes (such as migration to null safety, and recently deprecation of CocoaPods). Community very quick to update their plugins and adapt. Some abandoned plugins were immediately forked to keep being maintained.
- Migrating to native platforms, easier for agents to read an RN project. I'd argue it should be _easier_ to do that with Dart since the language is less "ambiguous" than JS.
However it's not perfect. My complaints:
- Not ideal for web apps with lots of FIRST-time visitors, due to initial download. There are some attempts to solve this, e.g. deferred loading, but I think inherently it's unsolvable since you need to download the whole world (a few MBs) to have the app running on your browser. That's why for this scenario I use SvelteKit. But if you already have a mobile app and want to get a web app "for free", this is a useful feature.
- WebView support is inconsistent across platforms (I'm looking at you, Windows and Linux).
They still haven't got native scrolling perfect for iOS. I used a big name app just today and I could instantly tell without looking it up that it was a flutter app, because the scrolling felt non-native.
You definitely should, it's grown a lot and Dart 3.0+ in general is a much nicer language than before, due to adopting functional features as well as having a garbage collector.
> it's unsolvable since you need to download the whole world (a few MBs) to have the app running on your browser
another reason why the web should move from whole app bundling to content addressed CDNs for library code. you would only need to download one copy for each framework version not every site. and its easy to make it decentralized with IPFS if you want.
To be honest I never tried and never have the need, as usually I either don't care about the font (use default) or I really care for branding purpose so I always bundle it to be sure.
While all of the points you brought up are valid, I've hated every react native app I've ever had to work on.
Not because of react native itself, but because they usually take random react developers to work on these apps and the structure they create is absolutely horrible to work with (compared to, for example, native apps).
What was your experience on that aspect with Flutter?
I agree. RN has historically attracted a lot of web developers who treat mobile like a React website, and the result can be terrible. But I've seen exactly the same architectural problem in Flutter: huge widgets, mixed responsibilities, state everywhere, and very little separation of concerns. The framework doesn't protect you from bad engineering.
Ah, that's a shame to hear. I would only like to add that at least for Android apps that I've been "hanging around" (my team never really worked on them), the teaching materials that are provided have generally made them a lot more pleasant compared to the RN stuff.
No framework prevents bad engineering. If a tool is rigid enough to make messy code impossible, it becomes too limited to build anything non-trivial.
Aren't you conflating framework design with dev discipline? You can write a monolithic disaster in React, native iOS, or Flutter with equal ease. Bad architecture usually happens when devs copy-paste habits from web or imperative paradigms without adapting to a declarative model.
Flutter actually gives you great primitives for clean code. UI components are lightweight config objects, so breaking a huge screen into tiny, modular pieces has virtually zero performance penalty. Its state model naturally separates logic from rendering, making it easy to isolate business logic into testable layers. Plus, the built-in analyzer catches anti-patterns like memory leaks at compile time.
all the tools to enforce separation of concerns are there, imo
The case of RN is different: it's made from a web point of view and applied to mobile. Therefore, it's not per se about the framework, but rather a coincidence that mobile and web are two completely different worlds. Hence, it's quite normal to see abominations when you allow people who are used to the web to do mobile development.
I was forced to migrate from pure native development to React Native and Redux is one of the stupidest things I ever witnessed. Or at least the way the previous devs setup that thing, because it’s so easy to make costly mistakes with it.
I lost so many days of my life profiling and debugging to figure out why hundreds of components were re-rendering when a tiny thing changed somewhere completely unrelated
There's simply a ton of teams that also never updated.
My previous team was not using RTK and our redux setup was extremely confusing to me (a backend engineer).
As someone who used all these frameworks professionally for years, I highly agree. Although, I do not prefer Expo due to it's highly annoying build system and dependency hell, but React Native itself in that case. While I understand Google wants a horse in this race, Flutter doesn't feel like a horse to bet on.
- Dart is a really _ugly_ language with lots of tiny annoyances. Its as if someone took worst parts of Java and Javascript and turned them into a language. Terrible to write, terrible to read, terrible to use.
- While there is no Skia anymore, the whole custom rendering of Flutter often caused more trouble than not, from the UI implementation itself all the way to specific low-end chipsets not being supported.
- Ecosystem propagates these insane architectures that don't make much sense and are made to either print apps as fast as possible or to emulate some Clean Code like behavior.
- Web still feels terrible to use, even after all these years.
Since I'm not happy with any of these, I've even taken upon writing a framework of my own that renders into native UI and works with any language (gonna shill it here https://hypen.space). It was inspired directly by years of working with mobile and experiencing the pains of crossplatform development such as Flutter and Expo. We can do better than these!
The internal divisions with this are really amusing. The big driver towards Flutter seems to be needing an iOS app, but Google really underinvests in those (YT being the exception, but it might as well be a different company).
Companies at the size of Google naturally have different business units with different goals. Flutter solves something from some teams with other parts of the company that do not solve for them. That doesn't mean there are some sort of systemic problems. It just means that it operates more like a series of smaller companies in many ways, which is overall healthier for everyone. It's confusing that everyone always expects some sort of unified strategy from the top. That's like suggesting countries should act more like dictatorships rather than democracies.
I mean yes, but also no. Companies the size of Google still have an overall strategy, and when one group’s strategy is to shit all over another part of the company, that usually doesn’t work out. Even worse, the scale Flutter is developed at is simply completely different than Android and Chrome. Flutter is really a symptom of just how strange Google is, as kind of a weird, anarcho-engineering collective where you can do anything as long as you can get a VP to support it.
I love working with Dart (which IMO is _not_ "worst parts of Java and Javascript (...) turned (...) into a language", "Terrible to write, terrible to read, terrible to use" - quite the opposite, actually) and its toolchain, including Flutter.
I find the architecture simple to follow, no need for "either print apps as fast as possible or to emulate some Clean Code like behavior", though I do think some people use overcomplicated state management solutions. But nobody forces anybody to do that.
My experience with Web has been fine so far and I've seen fully cross platform Flutter apps working absolutely fine on mobile, desktop and web.
This is not to gaslight your experience, YMMV after all.
And React Native, with its dependency hell, project rot, npm ecosystem under the hood, and transpilation with lax runtime leaking into TS, is a total no-go for me. Though I base this opinion partially on my experience with NodeJS, and partially on that of my friends who use RN.
Btw. Does your platform support bundling UI in addition to streaming it from the server? How large is the bundled runtime?
>I find the architecture simple to follow, no need for "either print apps as fast as possible or to emulate some Clean Code like behavior", though I do think some people use overcomplicated state management solutions. But nobody forces anybody to do that.
Unfortunately sometimes you have to, and on average, that code is much worse than your average React Native spaghetti. Whole generations of Flutter devs got these patterns ingrained, and often times they make not just writing and reading code, but communication itself harder.
>And React Native, with its dependency hell, project rot, npm ecosystem under the hood, and transpilation with lax runtime leaking into TS, is a total no-go for me.
That was my stance too until the new architecture released - since then the framework has improved a whole lot, together with its build chain, and is the best way to do crossplatform nowadays.
>Btw. Does your platform support bundling UI in addition to streaming it from the server? How large is the bundled runtime?
Not yet unless you DIY it - currently you can bundle UI and runtime by integrating the Rust engine + renderer with your app, or TS + renderer itself.
There is work being done in a private mirror currently on bundling the whole app + runtime as WASM, exposing WASI interfaces to native such as storage, network, permissions etc, depending on how testing goes it should land in a month or two on the public branch.
> Dart is a really _ugly_ language with lots of tiny annoyances. Its as if someone took worst parts of Java and Javascript and turned them into a language. Terrible to write, terrible to read, terrible to use.
While I’m a bit ambivalent towards Flutter, I totally disagree with you on Dart. To me it’s a better version of Java/Typescript with a very mature cross-platform and JIT/AOT compiler. Admittedly there are some things I wish they would take from TS (like discriminated unions), and I haven’t tried “modern” Java either so maybe that’s improved, but even so, I rarely feel like Dart is getting in the way.
They probably just haven't used the latest Dart versions which fixed a lot of the "ugliness" (which I'd call pragmatism but regardless) like primary constructors where a class can just be a single line now.
And I mean, their entire comment is a way to shill their app so I wouldn't take much stock in what they're saying.
Yeah I have no idea how someone who has used all these languages can come up with a conclusion like Dart is “uglier”. I really want to know what exactly they think is ugly about it!
Mostly its the core syntax, it's terribly noisy. Also parts of the implementation itself. While I cannot enumerate the taste, I can give you some examples.
For example:
- Class constructors cannot be in definition headers, i.e. class Something(Int a, Int b)
- The whole final and const/static const mess
- required is annoying and really "slapped on"
- shorthand syntax is => instead of =, personal pet peeve
- positional, named and optional parameters segregation makes things noisy
- concurrency, in which an event loop sounds like a great idea but ends up causing pain with multi-threading and background work so you have to spawn diff isolates
- the whole `await fn()` vs `fn()` validity issue, where you can miss the await keyword and it still compiles is such a slap in the face. think now they solved it, but you could also have returns from non-return functions and vice-versa.
- `dynamic` and generics in the same language have caused many bad designs
- extension types also feel hacked on
- type inference is annoying and highly contextual vs out of the box
- Worst sin: DateTime.now() returns different things based on the platform its running on, making it highly unreliable for something so important
I don’t want to sound harsh but that’s the least convincing list of language misfeatures I’ve ever seen. Almost every point is so minor I am surprised you didn’t mention having to type semicolons and similar incredibly inconsequential things.
I am biased - but mostly because I have actively used these in my career for quite a while now and encountered pains with both writing new code, upgrading old code and worst, inheriting code or helping debug someone else's code.
When given a choice, I'd rather use bland React Native nowadays than Expo or Flutter - one is a legacy addon to a framework, while the other sounds like a good idea until you step on a nail or have to read some _bad_ code. And there is a whoooole lot of bad flutter code out there due to relaxed language semantics.
I created something similar to Hyphen at my previous job and while it was a big shift in mentality, implementing UI in the backend and having the apps consume that and render it with native components os really underrated.
> Although, I do not prefer Expo due to it's highly annoying build system and dependency hell
Highly agree with this. I'm almost done moving an app off it into React (web, not native) because the SDK upgrades kept including unlisted breaking changes to the point I can't upgrade anymore. Biggest culprit was Reanimated.
I migrated one recently into fully native Swift UI and Compose from Expo - modern models can do it over night, and you save yourself from the dependency hell that is expo.
I’ve been keeping an eye on hypen.space and hope it succeeds. What is the level of maturity now and are there any multiplatform app examples that are not trivial?
Oh wow, thanks! I never would have thought anyone was keeping an eye on it!
Regarding maturity level - I would yet say it's mature for serious applications with OAuth, local storage etc. Late alpha/early beta stage.
There are some semi-trivial examples on the landing page - most are just UI + input with DB or API fetching in the background, so nothing spectacular.
All of these are crossplatform and render in both web/desktop/mobile and web SDK's or inside the Hypen Gallery apps.
Biggest obstacles to maturity currently are:
- Does not have native platform channels yet
- Renderers need more optimization work
- Ecosystem needs more stability - i.e. test mode and studio still have hiccups
- Error handling and retry story needs improvement
- Some components are still a bit off across desktop/mobile and need syncing
- Resource references derived from state need implementing for better DX
- Protocol isn't binary yet so performance isn't all it could be
But recently things landed that improve maturity quite a lot:
- Accessibility defining & automatic inference has landed, where framework does the best it can to figure it out for you with no intervention
- Animation API has landed with a minimal DX to enable transitions and animations
- Most of tailwind surface is supported and implemented
- Performance improvements being released this week land it in "often 30-50% slower, but sometimes 50% faster than react". Will add benchmarks to docs for visibility.
- CLI improved by a large margin, with expanded template support and easy building
- Cloudflare worker adapter so you can host your app on a worker
There are some similarities, especially in some syntax ideas.
I'd say the core difference from the DX side is that Slint stylistically aligns more with CSS on some areas and allows things such as assignments, Hypen aligns more with Swift UI and separates those things from the UI completely.
Also the integration story is quite different, where Slint is more leaning into a "component integration" model, Hypen leans more into a "just a display layer" model with strict state/UI/action segregation.
I have a different perspective because I would put all these points as a negative for React Native except hiring.
React Native is actually Native so you feel all the pain of the yearly redesign by Apple and Google and the millions of different device quirks to manage which will break your app.
You have the Javascript ecosystem which is notoriously janky and hard to maintain over time, even more so as nobody else cares about making it work for React Native, you are a third-tier platform.
Then the performance, Flutter is actually more performant than native for very cheap devices (I've tested it), that's why it's so popular in India.
The language is unified and doesn't feel as ducked tape as Javascript is.
Since when does React Native use real native components? Last time I've checked it wasn't capable of doing ANYTHING with my phones NFC scanner or native camera...
With flutter I can just build a Kotlin component and integrate it easily into my app.
Also Flutters performance is extremely good, I dont know what you are on about. Our app is used on extremely old phones and has great performance. (I am not even a professional android/flutter dev, so I didnt optimize for performance).
You're mixing UI components with platform APIs. React Native does use native platform-backed views. NFC and camera access are separate concerns. If an API isn't exposed, you can write the native Swift/Kotlin module and bridge it, just like you would integrate native code into Flutter. Camera support also already exists in Expo.
The biggest negative with Flutter is web. Because most of the UI is canvas-rendered, DOM based tooling like session replay, analytics, accessibility audits, and browser automation require specific instrumentation. That reduces third party choices you have unless you invest in your own tooling and who has time for that. I can't imagine the situation is much better in mobile.
Like I said I dont have much mobile experience to make a claim. Native apps have their own view and accesibility hierarchy. But even there, React Native would be a better choice because its components become native platform views which would directly be located by 3rd party apps like Appium etc compared to flutter.
I have. It's still immature compared to Flutter and doesn't necessarily run native compiled code depending on platform, it can still be tied to the JVM. Not to mention how amazing pub is compared to Gradle.
* Language and hiring: TypeScript has a much larger developer pool. Dart is a solid language, but finding experienced Flutter engineers is harder.
* Platform model: React Native maps much more naturally to native platform concepts. Flutter owns much more of the rendering stack, which is powerful, but also creates another abstraction layer between the app and the platform.
* Performance: Flutter can absolutely be fast, so I would not claim otherwise. My experience, however, is that RN has required less work to get interactions and animations that feel consistently native.
* Ecosystem: RN benefits from the broader React, TypeScript, JavaScript, and native ecosystems. Expo has also improved dramatically and now covers a large part of the usual mobile platform work.
* Platform-specific features: neither framework completely eliminates native code. Things like widgets, Live Activities, Dynamic Island, extensions, NFC, and other platform APIs eventually bring you back to Swift/Kotlin anyway.
* Migration to native: if the long-term destination is Swift and Kotlin, I find RN a better intermediate representation. Its component model and platform integration are closer to native concepts, which also makes the codebase easier for agents to translate incrementally into proper native applications.
That said, these are trade-offs, not claims that Flutter is bad. Flutter has improved a lot, and for teams that want a highly consistent cross-platform UI, its rendering model can be an advantage.