I used to maintain Detox for iOS when I was at Wix, from 2017 to 2021. We ended up dropping support for Expo for plenty of reasons, some technical, some "political". The people reporting "issues" (more like asking questions) for their Expo apps, usually had very little technical understanding of any of the increasingly thick environment stack (the Expo layer, RN layer, UI framework layer, OS layer). They were basically web developers who were trying to emulate developing for the browser, with zero interest (and often, capacity) in learning any of the complexities of the aforementioned complex environment.
It was our experience the expo layer added a lot of complexity and many bugs, with very little ability of users to actually fix anything without "ejecting" their project away from that ecosystem. That was on top of the RN layer, which in itself was full of bugs. We would send users to report expo bugs to the expo team, and were first met by "just fix it on your end, you are detox!" type of comments from that silly community, and those that did report the issues, saw no reaction from the expo team, despite detox being one of the most popular testing frameworks in the RN world at the time (no idea about now, but back then, even Facebook was using detox to test RN itself).
At the end of the day, we decided the hassle was not worth the low quality user benefit, so we decided to drop support for Expo. It was one of the best bureaucratic decisions we ever made.
Modern Expo is very different and in 2023, Expo has full support for custom native code and isn't a layer, so to speak. Ejecting is gone. React Native has also become much thinner in several ways. For instance, developers write Kotlin and Swift with the Expo Modules API and uses JSI (RN's "JavaScript Interface") to directly bind the native methods to Hermes JS methods.
Relatedly, the developer demographic has grown and a lot more developers are adding Kotlin and Swift to their skill sets. They write JS and React most of the time while also writing custom native code when they need to. Most of the best Expo apps include custom native code.
Test frameworks have also grown a lot. I suspect the issues with Detox were often from developers looking to use it with the Expo Go starter app that doesn't support custom native code. These days I hear a lot of positive things about Maestro as well and there was a nice talk on it at App.js Conf earlier this year: https://www.youtube.com/watch?v=uoCzBdFCoqc
I'm glad to hear the tech and, more importantly, the community have improved.
By "layer", I mean custom controls and animation toolkits that get bundled in an Expo-enabled project. Those are in addition to the RN-provided ones. It all adds to complexity.
Expo Modules Core is the only module that is bundled in. It is a small runtime library that defines the Expo Modules API used by other modules, and adds about 150 KB to a production build of an app downloaded from the stores. A hello world iOS app made with Expo ended up being smaller than the same hello world app that used RN without Expo due to the Xcode settings.
There are also no custom UI controls or animation libraries bundled with Expo. The Expo Go starter app includes a preset SDK, and when developers create a build for the app stores or a development build of their own app, only the libraries they use are included.
IMO it would be a meaningful improvement for the react-native package to provide the minimal runtime needed, namely JSI, Hermes, Turbo Modules, Yoga, Fabric, and perhaps a few primitive view components like View, ScrollView, and Text. The package provides more than a library needs. Animations and gestures today are better served in my experience by modules outside of the react-native package, like Reanimated and Gesture Handler that use truly native gestures. React Navigation uses the system navigator UI and Expo Router adds file-based routing and universal links. Expo Image adds support for modern image formats like AVIF and WebP and uses mature, performant image libraries like Glide and SDWebImage. So there is definitely still work to be done that can improve quality and reduce complexity in RN.
I learned a while ago that is not worth using an abstraction layer over the official tooling (whatever Apple and Google provides you), even for small apps I was building one for each platform (as one dev).
Tried at the time Xamarin and PhoneGap, and bit later RN, each one has his quirks and things that works in one platform but not in other so in the end you end up building one app for each platform more or less, but with more bugs than the official ones.
I’ve come to the same conclusion. I began to build a very simple app about a month ago and as a Web Dev figured React Native would be the best tool. Having completed about 60% of the app, I’m going to trash the whole thing and restart with Swift/Kotlin. I’ve encountered too many “quirks” that end up burning a huge amount of time for what should be an inconsequential component.
Using Swift UI, or UIKit, has its own quirks. And then you need to shift mental gears with entirely different UI component paradigms.
I find most people making this argument haven't worked full time with one or the other.
If you're a larger company who can afford two teams/groups, or if you are working on something lower level like OpenGL or ML, it makes sense.
Having done both for multiple years, I can't understand when people think it would be faster to build separate apps. It's not even remotely close. You're swapping out doing bug fixes, platform specifics like push notifications, the occasional separate UI implementation, and distribution twice with doing _everything_ twice.
For some bizarre reason I haven't figured out yet, it seems like the "cross platform" choice is always the worst one.
So when people talk about cross-platform on the Mac, for example, it's always some JavaScript abomination, or Java, or Delphi (yes, seriously), or Go.
How about going the other direction and getting Cocoa running somewhere else? GNUstep, Cocotron etc. Gosh, that would actually make sense, can't have that. Literally.
In fact, one company did. Apportable. Google bought them and buried the tech.
On the flip side, Unity is massively successful, and basically every indie game developer who has found any success eventually ends up porting their game to it anyway, precisely because of the cross platform benefits.
The problem isn’t that middlewares are bad. They are great: Unity and Unreal, your browser, Java…
The problem is mobile apps don’t make money. Games and web services do. The OP is talking about low quality users. They’re broke! They’re not incentivized to fix their own problems either! It’s all just a blub for them. So middlewares improve for the audiences where they’re at least viable, and stagnate when they support something that no one should be bothering to do in the first place.
Game dev is a different beast and in most platforms the development/tools are the same or close enough, also when building a game you rely only in low level API (Vulkan, Metal, OpenGL, etc) from the main platform you are targeting. But when you are building an app then you use the hight level API, that means you don't need to deal with font rendering, etc. You could obviously build an app with Unity, but it will not feel native, also IIRC Unity is awful when you need to input text in your game (in iOS at least, not sure how's Android side), it appears a input element above your keyboard while when using the native UI the UX is different.
I've realized that I don't want an abstraction layer. I want a guardrail layer.
Previously, much of my draw to things like Expo has been the reduction in mental load for handling multiple different platforms. In theory, they're built by people who know the different "gotchas" and can help me avoid them.
In practice, something always requires you to dive into the underlying layers. At which point, you're just fighting with bug-filled abstractions.
As a solo dev simple apps are probably the only thing you can maintain two separate versions of? Complex LOB apps at businesses as a solo dev I could never imagine not using a cross platform toolkit of somekind. RN w/ expo is the best I have found out of all the cross platform kits by far.
If you have react experience I really suggest giving modern RN & expo a try.
> the increasingly thick environment stack (the Expo layer, RN layer, UI framework layer, OS layer).
This is at the core of my difficulty with cross-platform frameworks for Android and iOS. Dealing with the first-party stack presents enough problems on its own. Adding more layers to that easily compounds the frustration involved in getting anything done.
Expo was really lackluster when I last worked with react native around 2018/2019. I hear it has gotten much, much better now but I haven't tried lately
It has. I built an app using Expo several years ago and recently had to update it. Upgrading expo was a pain (as it always is) but the changes and additions in the latest version made so many things easier. And with custom clients, you can do a lot more now than you could before without ejecting.
It's the best way to build React Native apps, with very few exceptions, these days. (I have been building RN apps of all types since it came out in 2015.)
I've used Expo going on 3 years now, their development team is incredible. There are very few reasons to use base react-native over Expo anymore; They make upgrades to new RN versions easier, can support any custom native libraries, have an awesome build service (EAS), support OTA updates, their docs are great... I could go on and on. If you're a RN dev and haven't tried out Expo in the past year I highly recommend giving it another go - its not the Expo you remember before their custom dev-client days.
I haven't used react native in years. Expo at the time felt like a shitty add-on trying to capture some part of the app development process but I didn't feel it added anything.
Sounds like I s gotten a lot better and found an actual usecase. I'll have to check them out again.
Yea, felt the same but haven't used react native for years either. Some concrete examples:
- Generally a poorer developer experience (bugs, bad documentation).
- Couldn't use some popular/common react native packages. It needed to be compatible with Expo, and there was an expo specific version to use the camera for example. These would have different (and more) bugs. Trying to use any unsupported packages meant ejecting, a hell that might be similar to ejecting from create react app or using craco, perhaps.
- Wasn't really adding much apart from being "all-in-one", but unfortunately each piece was sub par to the original react native.
- Unfortunately the react native docs were defaulting to suggest using Expo. They still do that now: https://reactnative.dev/docs/environment-setup. And yet developers often eject from Expo, so you'd rewrite the scaffolding of your app without expo instead of ejecting. IMHO that's quite sad to see the React Native docs still suggests Expo.
Side note: I've been using Flutter for a few years now, much better developer experience. Doesn't have code push yet, but https://shorebird.dev/ is working on it. (I am not affiliated with them).
Last time I worked with Expo, the main historical reason for ejecting (custom native modules) was all but eliminated by the config plugin system. We actually ejected at one point, but rolled back that change once we realise the plugin system could do everything we needed.
I love these real takes. I had the exact same experience trying to get into React Native and Expo, eventually just decided to write native apps if I ever get into app dev.
I've been using Expo for past 2 years and I enjoyed the experience overall.
But make no mistakes that Expo is a SaaS with the ability to inspect some part of the codebase.
(I stand corrected here) ~Everything important for building and distribution process is moving to EAS, cloud-based service that is not open-source and cannot be self-hosted. So if want to build your app using your own VPS, you are out of luck (at least for Expo managed workflow).~
Again I'm happy with their service and probably would pay for it when the time comes, but the open-source part is not really the big selling point anymore.
You can use the `--local` flag to build on your own computer/CI/VPS. `eas build --local -p ios --profile production` can locally build you an iOS bundle. Don't expect it to work out of the box, though. Your machine should have all the XCode tooling correctly installed and configured. Works for Android as well.
> Your machine should have all the XCode tooling correctly installed and configured. Works for Android as well.
I mean that's the case for the 'regular' React Native workflow as well, and most mobile / crossplatform development. That said, yeah getting RN running is a bit more effort compared to Expo, but it allows for a bit more flexibility.
We decided against using Expo because we had a number of 3rd party dependencies (trackers, analytics, chat, sigh) that had native components; it can work with Expo, but the dependency has to implement support for it, and that was a bit all over the place.
The Expo setup that I use never calls into Expo servers at build time. For OTA updates, I've managed to get my self-hosted Expo update server working too, although I'm not using it at the moment, as its incompatible with the React Native New Architecture (it's the last expo package to lack this support - hopefully they'll add it soon).
The hosted services offered by the Expo team called EAS has an implementation of an updates server that conforms to that protocol. If EAS went away or you wanted not to use EAS, you could write and operate your own server that conforms to the protocol instead.
please do so, I would like to build it totally local and when I realize that outsourcing the build to the EAS cloud saves more time and money I will switch later, that sounds like a nice way to get more people use Expo.
I believe it still uses EAS for certificates by default. You can use "prebuild" to get the ios / android directories. Alternatively start a React Native app and install their modules separately. These options still work well but require a lot more setup.
Expo is the free and open source framework and, separately, Expo Application Services (EAS) is the SaaS. Expo and EAS are designed to be decoupled while also working well together, optionally.
The Expo framework gives you the module system, runtime environment, CLI tools, debugger, a suite of modules, navigation to build universal native apps. They're universal in that there is an Android build, an iOS build, and a web build, and, especially with Expo Router, they work together with universal links. They're native in that the user experience is native to the underlying platform, usually using system UI components and behaviors.
EAS provides hosted services for building your app, submitting it to the stores, and updating it. Many developers will use both EAS and their own hardware. It is convenient and fast to build locally when iterating on a feature. And it is convenient in a different way to use EAS to make preview builds of your app on your PRs that change your app's native code or to make release candidates for production.
Hey. I appreciate that there is a distinction between Expo and EAS.
However, as a user reading the Expo docs, I'm not sure if I can separate them easily without deviating from official docs.
Look at the Expo docs on building and deployment, which are essential steps to getting your app distributed. I don't see any mention of how to achieve it without EAS.
There used to be an expo build but it was deprecated a while ago.
A lot of the docs prioritize ease of getting started and EAS has a free plan generous enough to get you to production and often beyond. The Expo CLI docs have a section on building locally here: https://docs.expo.dev/more/expo-cli/#building
"npx expo prebuild" (covered in that link) is a good command to know. It generates "android" and "ios" directories with your Android Studio and Xcode projects, respectively. These projects can be built entirely locally and there is no dependency on EAS.
As a side note, the old "expo build" command also ran on hosted servers. It was part of the old Expo CLI, which, for historical reasons from six or seven years ago, didn't separate the free & open source Expo framework from the hosted offering. We built EAS years later, with a major new feature being support for builds that have custom native code. Keeping EAS decoupled from Expo has been a conscious effort, and we've also designed EAS to work with any React Native app whether it uses Expo or not.
I guess I'm just saying it would be nice to have an actual "expo build" command that can build the app locally (assuming Android Studio and Xcode are in place), to complete the full Expo framework experience, instead of using expo prebuild and letting the user deal with Android Studio and Xcode manually.
Then again, I can understand why it isn't a priority for the company.
I’m primarily a web developer that’s long been interested in native mobile environments and after trying out many of these cross platform frameworks (all the way back to Appcelerator for those who remember!) my conclusion always ends up that they’re almost always a bad idea. The experience is inferior to native, it’s full of compromises to make cross platform work and you’re at the mercy of a company standing between you and the underlying mobile OS.
My advice these days is to go in one of two directions:
- make a progressive web app. No, it’s not a native experience. But if your priority is cross platform then this is cross platform. Service Workers etc make it a ton more paletable than it was back in the day.
- make native UI and code your business logic in some kind of shared layer (Rust, Go, Kotlin Multiplatform). Native UI has come a long way too, as someone who speaks webdev I find SwiftUI and Jetpack Compose to be very grokkable compared to their predecessors, a lot like React if you squint a little.
After 4 years of doing cross-platform mobile, I loathe React and React Native by now, and I dislike Expo. But… suggesting any other alternative is tricky.
True native development is, indeed, much better. But a small team will be hard-pressed for doing good work on both platforms, especially once you start fiddling with more important APIs. Configuration and getting your system to compile things to properly is almost a job in itself. Sigh.
KMM, Flutter, and MAUI are all promising, but with different trade-offs.
So we’re stuck with RN/Expo… At least Expo promises some stability between upgrades, by handling the package compatibility checks for you. Well, when it works.
“Make a progressive web app”: yes, that might be the way to go; provided you can get the users to ‘install’ it on their devices. For some companies that’s not optional due to different pressures (e.g. teachers would expect students to have our app installed on their phones).
Neither of these 2 solutions is that simple. There are trade-offs involved, and each team must compromise where they can/are weaker. All in all, if you MUST do RN, at least Expo saves you a lot of headaches with config/build/compatibility. It’s mediocre, but worlds better than pure RN (at least for me).
I came across a standard notes blog recently about how they “migrated” to a single codebase by relegating RN to render a single component of their web view, which is the same view that’s rendered in their desktop app and website, using a native “DeviceInterface” wrapper for each OS.
Sounded like a preferable approach to dealing with the complexity and limitations of RN and multi-platform. I wonder why more teams haven’t gone with this type of approach…
> “Make a progressive web app”: yes, that might be the way to go; provided you can get the users to ‘install’ it on their devices.
Assuming you're talking about the not-well-known process of adding PWAs to the Home screen, it's worth noting that you can package web apps for app store distribution as well. https://capacitorjs.com/
This seems quite good, if reviewers don’t reject the app on the basis that not enough of it is native. We’ve gotten push back from Apple for all sort of minutiae.
That decision completely depends on the context. For a small team, without too much native experience, I'd still 100% recommend using expo. It's just going to be easier for everyone with less bottlenecks and less code to maintain.
If PWAs were actually used by the mass markets, I'd go with that option, but the fact is they're not, and you can't expect to force your users to learn a new behaviour like that.
> For a small team, without too much native experience, I'd still 100% recommend using expo.
Maybe I'm too optimistic but as a web developer I loved being given the opportunity to learn some Swift and Kotlin. Compared to Objective C and Java they are really very approachable for JS devs and with not all that much work you'll end up with a deeper bench of developers more satisfied with their jobs.
Looking to always learn new things is great. If you find yourself looking to try out Expo and have completed the first setup steps, I'd suggest looking at making a development build of your app and the Expo Modules API for writing Kotlin and Swift code.
Almost all of the best apps made with Expo also have a small amount of custom native code. And I find it's just generally good to understand the abstraction layer above and the abstraction layer below the one you're working at to bring the two together the best you can.
Almost no one knows what a progressive web app is. And for most people, the only way they use the internet on their phones is through apps. It just doesn't occur to them to do otherwise.
I wish things were different. It would have saved our company almost a year's worth of development on a pwa.
This is highly dependent on your target market. On Android PWAs effectively are apps as far as users are concerned, you can even make a “WebAPK” and submit it to the Play Store.
The story on iOS is much worse, naturally. But if you can get past getting users to actually install the app the rest of the experience is acceptable.
Can’t we disguise the PWA as a browser on the iOS App Store? So in theory it’s just another browser that only allows to open one website- the PWA. But on the surface, to the users it will be available as an app in App Store.
It is technically possible, of course, though I vaguely recall iOS App Store guidelines saying not to just wrap an existing website in a webview. On the flip side, PWA support in Safari has been gradually improving with better support for web manifests and web notifications, for example.
Part of Expo's approach is for Expo apps to be native apps that provide a user experience that is native to the underlying platform, whether it's Android, iOS, the web, or something new.
For instance, navigation is one of the more complicated parts of an app's UX. The navigator UI has many subtle behaviors and animations that have been built over the course of several years, like how the back button and screen headers transition in and out. The gestures often have invisible hit boxes that are hard to replicate without using the system UI components. The screen transitions use specific animation curves users expect. And there's non-visual behavior like supporting universal deep links that take the user to a specific screen, which tends to require quite a bit of work to implement.
Expo uses the system UI components and the behaviors described above are present. The goal is for Expo UI to be native UI. And in some aspects, Expo can already provide a better default user experience like with universal links. Every screen gets a URL with Expo Router since URLs are a first-class concept, like they are on the web. This lets us provide deep linking (navigate from URL to a screen) and universal linking (HTTPS links work across web and native) as default features.
Sometimes the way we talk about Expo is that it brings together the best of native and web, and a lot of that is the user experience of native applications with the developer experience of the web.
Flutter is the second nicest platform I've found for developing for Android (losing to Jetpack Compose) and best one for cross-platform. As a user though, I hate using Flutter (and non-native) apps for simple things. They often look totally different from the rest of the OS. For products that exist as something other than apps, it's fine, but I still prefer native Material You apps.
The best Android app for a product I've used is the AnonAddy app. It's stylish Material You while feeling very custom and tailored.
I remember Appcelerator. In fact I'm still using it to this day. The core Titanium is now open source and the Apps are "true" native. Give them another look and you may be surprised: https://titaniumsdk.com
As a designer specialising in mobile apps, I have to say nothing still comes close to native codebase experience. Expo & RN is fantastic for MVP (and I've been a super early adopter of RN back in ~2014). But once you start building anything serious, you will very quickly start hitting the walls.
As an example, some time ago, it was impossible to implement those iOS large headers that shrink to small once you start scrolling. Even though they were de facto standard in iOS for years already. Also the heavy layering of modals introduced in mostly in iOS 15 were basically impossible. Plus they heavily rely on subtle transitions like the 2nd layer scaling down, moving back and top edge peeking out at the top, so that the user gets a hint where they are in the hierarchy... Not sure if all this stuff works now, but generally Expo & RN were very slow to catch up with iOS and you had to rely a lot on dubious libraries, ending up with messy patchwork.
All these minor details are extremely palpable, even by standard users, and the experience just always feels a bit off.
It’s possible to do all this stuff in RN - you just need good native bindings to the features
Stuff like the iOS 13 page sheet modals being broken is still an issue - but there’s a set of present/dismiss callbacks in the modal manager you can override in your code to fix it
Not sure if you meant page sheet controllers for iOS 15 (the ones that let you pin it half way up). There have been implementations of this, but they all suffered from a kind of crappy animation when you overstretched the page past its allowed limits. iOS would normally force a layout, then animate between the last layout and the new layout. But since RN’s layout is asynchronous, iOS couldn’t perform the animation and it looked sloppy
If asynchronous layout were the culprit, presumably that's the precise type of issue that react-native-reanimated solves? It seems to me that the experiences created via react-native-reanimated run quite smoothly indeed. Of course, the developer still has to reimplement interactions otherwise provided by iOS etc, but React Native should not be a reason for things like sloppy interactions.
The animated package doesn’t come into play here. When the layout needs to be recomputed in RN, it does it asynchronously - regardless of what’s calling it. Part of this can be explained because the JS can hook listen for layout updates via the onLayout prop and make changes to the layout - and could in theory cause infinite loops. But there’s no mechanism - as far as I’m aware - to say you don’t care about that detail and just do it synchronously anyway
I believe you're confusing react-native-reanimated (https://github.com/software-mansion/react-native-reanimated) with the Animated API from React Native. react-native-reanimated allows JS code to run on a UI thread that is able to synchronously modify layout, providing alternative synchronous ways for you to hook into the layouting. For instance, as opposed to the asynchronous `measure()` method provided by React Native to measure layouts, react-native-reanimated allows one to call their version of `measure()` (https://docs.swmansion.com/react-native-reanimated/docs/api/...) to perform the same operation on the UI thread, synchronously.
I meant both Animated APIs - neither is able to perform synchronous layouts - because react native is not able to do that. That’s the issue that’s stopping the page sheet controllers being added to react native. I actually was helping getting this added, but we never managed to get the layout issues fixed - https://github.com/facebook/react-native/pull/34834
The measure function you mention isn’t co-ordinated to the layout, so you could read it while a layout is pending and get old data - but that doesn't really matter for most cases
They keep saying you can do it - but I can’t actually see how. I don’t do a whole lot with the new architecture at the moment - it’s still very new and a very bumpy ride if you want to adopt it
One part of Expo's approach to UI is to create native user experiences. For several years Expo has invested in React Navigation and Expo Router, which use the system navigator. For instance, in iOS apps made with Expo in 2023, your headers will resize as the user scrolls and layered modals are natively supported. Details like showing the navigation stack when long-pressing the back arrow are supported from day one because Expo apps are native apps that use the system behavior.
In contrast, 2D UI frameworks like Flutter, Silverlight, and Flash replicate the system UI. In my experience it is possible to create a replica that visually looks like a pixel-perfect match but it is very difficult to make the replica behave the same, like the rendering the subtle layer transitions you talked about, invisible boundaries around gestures, and showing the navigation history stack. It is an uphill task and using the native system UI is a tailwind for Expo.
Tbh, I liked expo, but since you cannot build locally nowdays (you can eject and build, but that won't work 99% of the time, literally didn't work for me on the hello world example), I kinda just threw it in the "cool, but won't use" bucket for time beeing :/, could change in the future, but I don't know how I feel about 3d party service (EAS) building my app and holding my signing certificates (yet)
The Expo Go app needs to connect to a server for two reasons: the server gives you a signing certificate that is used to sign your project manifest, and it also fetches the list of active and recent projects and Snacks. It is certainly not intended to be invasive.
Expo Go is entirely optional and it is recommended to graduate early on in your development cycle to using a development build of your own app instead. Development builds don't sign project manifests (unless you're intentionally using end-to-end signed updates, an advanced feature). They are like regular development builds of a traditional native app.
Also if you'd like to keep using Expo Go, the signing certificate mentioned earlier has an expiry of 30 days or so IIRC, during which time you don't need to connect to a server. You may still want to provide the "--offline" flag to turn off refreshing the certificate.
FYI I've made a patchset that pretty much allows me to actually use the EAS --local builds offline and without an EAS account, so it's in fact possible, even though they, for obvious reasons (e.g. https://github.com/expo/eas-cli/issues/1606), don't encourage it.
Would you mind sharing this? I’ve only used expo for experimental non-production apps so far but it works be great to be able to do this if ever needed. Reading this thread makes me a bit more hesitant about using expo.
My full build process is somewhat more complicated to keep my $HOME clean and remove other impurities, but just these patches should be enough to enable offline building.
EAS CLI is designed for EAS, the hosted services. It is intended to use your EAS account, which I suspect is why the PR wasn't accepted.
Expo CLI is for entirely local builds. Run "npx expo prebuild:{android,ios}" to generate your Android Studio and Xcode projects, and build them with the IDEs or their respective CLI tools directly.
You can build locally without ejecting; just throw the --local flag on the end of your eas build command This does what EAS would do, just on your local machine. If you remove the --local flag, it will send it up to EAS to do the build.
eas build --profile develop --platform ios --local
yes, you are right, however, AFAIK you still need to be logged + have it linked to eas project (because it uses eas credentials) + this method is planned to be deprecated soon [?] (I'm 100% sure I read stuff like this when researching it like half a year ago, but cannot find it for the love-of-god atm :D, but I would like to be proved otherwise, because the build step is the only thing I disliked about expo long-term wise)
... now looking more into it, I probably mistook `npm run export` / `expo build` with `eas build --local`. Is this correct?
I think your commands are kind of muddled. By `npm run export`, I assume you are referring to `expo export`? That is responsible for bundling your app for OTA updates. `expo build` is the deprecated method for building your Expo app with the old ExpoKit native shell app. Only `eas build --local` is the actual command for locally building your app.
Perhaps the issue you're thinking about was what I linked to in my other comment?
By my own thinking, I believe it's quite unlikely that Expo will ever manage to actually totally remove support for local builds, even though they probably will never encourage it; as otherwise, its really quite impossible to debug native builds, and indeed local builds are Expo's recommendation for debugging such issues. With regular React Native native dependencies now possible in Expo, a dizzying new array of hard to diagnose bugs can now be triggered, and its unlikely Expo is ever going to go back on their support for arbitrary native dependencies.
Yeah, afaik, in the old template version `npm run export` activated the `expo export` and THAT got deprecated (recently), however at the time (about half a year ago) I thought that the `--local` flag was getting deprecated. Sorry, that was a huge misunderstanding on my end!
Building Expo apps on your own hardware is definitely supported. Specifically, run "npx expo prebuild:{android,ios}" to generate your project's "android" and "ios" directories. Open them up in Android Studio and Xcode (or use their command-line equivalents), respectively, and build.
The managed services (EAS) are optional for Expo apps. The independence between Expo, the free and open source framework, and EAS, the hosted service offering, is something the Expo team consciously works on.
Building Expo apps locally is not going to be removed. I am one of the cofounders of Expo.
Being able to build your app on your own hardware is a relatively fundamental feature of any application software framework. The Expo framework is free and open source and we consciously keep it decoupled from Expo Application Services (EAS), which is a suite of hosted services we manage.
Two of the ways to build your app are:
- Entirely locally, without EAS: generate your native Android and iOS projects with "npx expo prebuild:{android,ios}" and build your app with Android Studio/Gradle and Xcode/xcodebuild, respectively.
- With EAS: after getting set up with EAS, installing EAS CLI, and configuring eas.json, run "eas build". There is also a "--local" flag that runs the compilation steps locally and uses your signing credentials managed by EAS.
Many developers use a mix. For instance, they'll build locally when working on a feature for a fast feedback loop. And they'll use EAS to build their release candidates and PR previews to share with their team.
However, making your apps depend on a framework has the following dangers:
- the framework might stop being maintained
- the vc-backed framework might need to become monetized beyond your means
At the end of the day, all these frameworks offer are convenience APIs to easily integrate with native things like push notifications or social sign-ins
However, even when these work, they will force you to do things their way, and you won't be able to fully customize your app
Learning how to do these things natively in iOS and Android requires extra effort but pays off in the long term. Using frameworks, the time saved in the beginning of your app development journey will be greatly offset by the extra time required to do things like editing framework output in each build towards the end of your journey
These are a few things I can say as one of the Expo cofounders. We've worked on the Expo framework for over eight years, and did R&D for a year or two before that even before React Native was released. Many other companies and frameworks, even from very large companies, have come and gone in that time and Expo has endured. Paul Graham wrote he found determination "to be the most important quality in startup founders" for what you find that to be worth.
Also from the beginning we believed the Expo framework needs to be free and open source. Introspecting as developers ourselves, we thought people would be a lot more likely to try out and recommend open source frameworks and incrementally build up an ecosystem of modules and StackOverflow answers. Expo gives developers much more agency because it is open source. And it is really hard in my opinion to make a business from licensing developer tools, libraries, and frameworks. There are so many free alternatives.
The goal of the Expo framework is to be the ultimate way to build universal, native application software. Universal apps have builds for Android, iOS, the web, and future platforms. And the user experience is truly native to each respective platform, often by using the native system UI components and not a replica. It does take significant effort to maintain the Expo SDK's set of convenient APIs. It's also just one part of Expo overall.
Separately, the way we are building a business is by offering hosted services for React Native apps, called Expo Application Services (EAS for short). These are optional services for building and updating your apps and using the Expo framework doesn't require EAS. We find developers often use a combination of EAS for some tasks and their own hardware for others.
We work to build developer trust. We are a small company but try to serve developers and our customers well, sometimes better than the companies that have endless trunks of money (we've all seen killedbygoogle.com). So, that's some of how we think about things at Expo.
...and I of course wish you every bit of success. The root cause of many problems is Android and iOS specs changing every 6 months in a not backwards compatible way. It makes maintaining any framework an even bigger headache. I hope you have the determination to keep your level of support high enough to overcome this
I also work for Infinite Red (leading RN consultancy) for the past year, help maintain Ignite boilerplate and also have used Expo since diving into React Native back in 2018-19. Even during the early days of Expo, it served me well across 3 startups to quickly get our app running on both Android and iOS. Now that it's more mature, the possibilities are endless. There are no snags or scenarios that you can no longer accomplish.
For everyone that tried it in the past and has been reluctant due to the "old Expo" of the ejection days, you definitely need to give it another try. In the industry we're in, we all know technology changes rapidly, so to not adjust your mental model after 5 years have gone by is doing yourself a disservice for sure.
The RN template upgrades are painless. It enables you to develop on any operating system, which is a big forgotten perk. You can build in the cloud if you want, but you can also build locally (via EAS or the RN cli, this is important Expo apps are RN apps and vice-versa).
Need to drop into Native code? You can do that very easily now. It's not a show stopper. Need to whip up a quick demo app for a presentation? It works there too.
Oh yeah, do you find the app store dashboards painful? Send it over with EAS Submit all via CLI. You can even set this up in your CI if you want.
Preview PRs on release channels via EAS Updates, also amazing. Your QA will love testing features in isolation. Your management will love having the product testable on their devices and you won't get bogged down when they want to see the latest and greatest for some demo you don't need to be bothered with.
The team is made up of incredible, hardworking people who want the best for the native application scene. They want the best for your development team. And that's awesome!
I'm a huge Clojure(script) fan, re-frame is an amazing and super elegant/easy development tool. The awesome this is you can use Clojurescript and Expo together. It was one of the absolutely most pleasant development experiences I've had, especially supporting multiple mobile platforms too. I've also done Android dev and used a Ruby + iOS toolchain before, and done a lot of mobile web. Expo + Clojurescript easily brought the most delightful experience. Interacting with their team was also fantastic, very smart and responsive.
I'm not there yet but totally intended to try putting Clojurescript and Expo together. Too many ideas require apps and Clojure is too great not to take with me yet I wouldn't do apps without Expo.
Exciting! Thanks for sharing!
I'm on re-frame too and that's been a dream.
I just wish I had a better UI lib on the (web) frontend. I went with re-com and it feels a bit half-done, though it's working for all my needs so far, I might just sending PRs if it comes to it.
Expo 49[1] was released earlier this month which includes network and VSCode debugging which will make life easier. Even though I registered my Expo 48 mobile app[2] with EAS and did Android + iOS builds, I never received an email about this upgrade...glad this is posted on HN!
This is the impression I've gotten recently testing their waters. Overall, my take has been to stay away from it unless the app I'm making is simple enough they have templates floating around the web and won't need further tweaking: similar to wordpress, great to have a certain type of app up and running fast but the minute you have to do extensive work on it, you'll wish death on it.
My primary issue with it is the lack of support for in app purchases (last checked in late 2022).
The only easy way to do it is via RevenueCat, as none of the other RN IAP libraries work with Expo.
Expo also has built in support for over-the-air updates, which is great. However, it is a paid product, for $5/m per 1000 users (first 1000 free).
I believe you can run your own server for OTA updates, but it's fairly obvious that this feature will eventually be removed when they need to monetize harder.
Expo these days is pretty extensible and the option to write your own IAP module is a bit easier with Expo Modules, which let you write custom modules with Kotlin and Swift and set up a config plugin to automate changes to your Android Studio and Xcode projects. It definitely would be good for more IAP modules to provide config plugins and automatically integrate with Expo.
The ability to write and run your own update server is a part of Expo Updates and it is not going to be removed. The Expo Updates protocol is an open specification here: https://docs.expo.dev/technical-specs/expo-updates-1/.
Separately, EAS provides an optional, hosted service that implements the server side of the standard Expo Updates protocol and supports both simple and more advanced deployment patterns, for instance: https://docs.expo.dev/eas-update/deployment-patterns/. It also integrates with EAS's build service and appeals to teams looking for managed cloud infrastructure.
My company is moving our app to React Native and evaluated Expo as an option. Our conclusion was that we needed some of the features that using Expo doesn't let you use (a lot of native modules, as we're not rewriting 100% of the app all at once).
Additionally, I think RN has come a really long way from where it was when Expo first came about. Expo sought to smooth over a lot of rough edges, some of which no longer exist.
I think Expo realizes this as well, as their main revenue generator is now their deployment tools. The framework is opinionated toward using those paid services, which my org doesn't want to use as we already have processes for building and deploying, which makes working with it cumbersome.
Expo supports custom native code including your existing modules. It is a much smaller step to start using Expo if you are already using React Native.
Using Expo without EAS, the paid services, is definitely supported. The Expo framework is free and open source and is designed to be generally decoupled from EAS. "npx expo prebuild:{android,ios}" will generate "android" and "ios" directories that can be built with existing build processes.
Expo: free and open source framework. Includes Expo CLI, Expo Modules, Config Plugins, Expo Router, debugging tools.
EAS: hosted paid services. Includes builds, submissions, updates, credentials. Works with any React Native project whether or not it is using Expo.
I work for Infinite Red (leading RN consultancy), and we have really bought into Expo in full force in the past year or so. The addition of EAS, and prebuild with config plugins has completely changed the game and for us and all but eliminated the need to ever do bare workflow anymore.
Things we love about the expo ecosystem
- React Native upgrades are much less painful if you use prebuild. Upgrading the expo SDK takes care of most things for you
- EAS makes distributing and managing certs incredibly easy
- Most expo packages (like expo-camera, etc) are some of the best out there and very well documented and supported
- The Expo team is incredibly talented and always willing to help if issues arise.
I think there is a lot of confusion around what Expo provides. You certainly don’t have to be using their managed workflow to take advantage of the platform.
I’ve used Expo modules and services at both Tesla and SpaceX for building large scale apps. I’ve consistently found that their modules are some of the best maintained in the ecosystem.
One of the biggest technical risks we face is building a feature around a module that is later abandoned. Using Expo, we don’t really have to worry about this. Web support is also a huge plus (web support in other RN packages is hit or miss).
Slightly off-topic: how practical is it really to build devices (iOS and Android) and web from the same code base?
My poor understanding is that React Native, and hence Expo, doesn't use the same CSS frameworks as web development. I'm curious how that works from the same code base, or perhaps that's one of the major difficulties.
Also I see Expo as a fancy build framework but it's still fundamentally a RN application. Is this correct?
(My front-end colleagues are on another continent and we don't get any water-cooler time. Sorry for the possibly awful questions.)
I’m not using Expo but I do use Capacitor+Quasar to build cross platform apps to great success. I use it for my job and for my side business. Without it I doubt I could run my side business because I just don’t have the time as just 1 person to maintain 3 codebases.
I’ve never used Expo, React Native, or Flutter so can’t speak to those but I’m pretty happy with my setup. Yes I have to put a tiny bit of logic behind checks for if I’m on the web or if I’m in an app but it works surprisingly well overall IMHO.
It has become very practical / doable in the recent year or so. In my experience, if you have lot of frontend web experience, the easiest way to ship a RN app is by using Solito [0]. Also check out Nativewind [1] which allows you to style native apps the same way like you would on web. I was able to ship the first version of our app in about 1.5 weeks with this stack. Also checkout Tamagui [2].
Solito seems to let you share component code, but I assume that it does not share data fetching code? It doesn't do SSR for the native app? And in expo you'd be expected to `fetch` or otherwise get the data yourself (compared to next land where you can just use the next data loading stuff)?
Using Expo and React Native for web is not really practical. But simply having your mobile and web applications both in TypeScript you can share bits and parts of code, most notably the types & data models, application logic code, and assets (from simple image files, through lottie animations, to strings & their translations), but also potentially run some parts of your web application in a webview, ...
I have never attempted to use the web target of Expo, and probably would never try, not the least because so many dependencies assume that the target of a React Native app is either iOS or Android with the web having such different APIs, and the plethora of alternative options for the web.
The ‘and web’ bit I’ve never found to work well. There’s too many things that work differently on the web
As for the CSS part - yes, React Native uses order for priority, web CSS uses specificity. None of the attempts to get the RN way working on web were amazing
It's RN with less (or I guess different) steps, actually; you can skip the bit where you have to manage and build the native parts of your apps, even though with RN that's already minimal, manageable and works out of the box. generally.
No I don't think so. Next.js adds a truckload of functionality to React, plus handles the server side, etc.
Expo aims to abstract away everything that a web developer wouldn't inherently understand when moving to mobile, i.e. the native stuff. Whether or not it succeeds in that mission, or if it's worth it, is up for debate.
Is there anything equivalent for Vue? I know there was VueNative and NativeScript and there is even Ionic in Vue, but haven't really seen any framework that is either dedicated to Vue or has a strong support for Vue.
Quasar+Vue (uses Capacitor as well) has worked very well for me. I used Ionic with Angular years ago and I know they support Vue now but their support wasn’t great last I looked (it’s been years, this might have changed). Quasar is Vue-only and benefits from that focus.
The title made me think they were trying to rebrand as not being limited to React Native. I think they are instead trying to market to a wider audience by not mentioning React in their tagline, though.
Expo and EAS is my preferred choice for building a new product these days.
I was focused on native Android development (Java/Kotlin) for many years. React Native (I first used in late 2016) and Expo (I first used it in production in early 2020) have matured so much over the last years and all the Expo tooling is a game changer for building (cross platform) apps.
A few examples of how Expo has changed the game:
- The Expo Go or Expo dev client make it possible to no longer need XCode or Android Studio during development and thus make it much easier to bring engineers onto a project who do not necessarily have mobile dev experience. The dev client can be built locally by one engineer and shared with the team or can be built in the cloud with EAS Build.
- Upgrades in bare React Native projects used to be painful and time consuming. With Expo prebuild, one can (re-)generate the native projects at any time including after upgrading to the latest RN/Expo versions. Further this allows having to never source control the iOS/Android folders.
- Expo config plugins have made it possible (and really straightforward) to apply modification to the XCode/AS projects such as adding permissions or adding extensions. Requiring modifications to the XCode/AS projects used to be a reason for having to use bare RN / eject from Expo.
- The Expo Modules API has made it really simple to create a library project and allows for writing the native code in Swift/Kotlin. Setting up and maintaining a RN library used to be a lot more involved especially if it was small and not touched very often.
- The entire Expo EAS offering basically provides you with what normally a mobile ops time would provide - builds in the cloud, app store submission and ota updating. For anyone who has set this up with Buildkite/App Center/CI tool knows how much time this could cost / take.
And these are just a few things that are top of mind.
It is my experience that using Expo + dev client, allows me to bring together a team from all backgrounds (iOS, Android, web, backend) and quickly get everyone up and running, contributing and have impact.
The first product I built with Expo was HowWeFeel (April 2020) and with a small team we shipped the initial version iOS, Android and web in less than two weeks. The most recent product is Pinterest TV Studio and because of Expo/RN it is feasible for us to have it not only available for iOS but also Android.
I'm excited for the future of Expo and curious what will drop during launch party (August 8th).
Sometimes I tell people the best Expo apps have custom native code and it is a really useful skill to know Kotlin and Swift in addition to React and JavaScript. Glad to hear you have found Expo and EAS so useful! One of the features we'll be previewing during launch week is something Pinterest has been needing for a long time, and we'll make sure you hear about it.
I just want to write Svelte and get native apps out the other end. I know we have SvelteNative but that's not great and is a big abstraction. React here is a bit of a bummer i'm not going to lie.
This sounds like the inevitable slow death of RN to me. Web developers simply moving on to new tech that's better/more common on the web while RN languishes as the massive set of open source libraries required are abandoned
Don't confuse HN bleeding edge hipser tech with the real world. The world of react-alternatives is fragmented and lib-incomplete, React still gets more installed than its most popular rivals combined[1].
I have worked across these frameworks and React is the only one where I find the lib ecosystem satisfiyingly large (and still growing most steadily).
It's so weird there is no mention of react native in github README, they only mention react. Did anything changed and expo is not based on react-native?
I believe you could do it by writing a config plugin[1] that will apply the desired config changes to the native project files.
Expo will apply the config from plugins when they are building the native app for you.
(Disclaimer: I use Expo at work for cross-platform app including web but never wrote my own plugins)
This was my main criticism as well, but not anymore.
With the "prebuild" workflow you can regenerate your iOS and Android projects anytime you need. And set up scripts for adding external libraries in the process.
It is more work to set up over just altering the native projects, but the result is rather nice.
I've never felt 100% confident that react native project folders wouldn't break for arbitrary reasons. Being able to so easily start over is very useful.
This is actively being worked on. Also a big area of investment over the past couple of years has been adding support for custom native code to Expo and the Expo Modules spec. It is easier in several ways now to write your own module when an existing one doesn't work for you.
I’ve very much enjoyed their libraries (though not their monorepo changelogs) in building our RN app. Seems like from the comments the situation we found ourselves in where “bare” react-native was the only option is the best way to interact with the ecosystem from the outset.
A few years ago our main concern with Expo was about security, man-in-the-middle kind of attacks because you are hardly depending on a third-party, has anything change to robust this? I understand that to general apps Expo could he a dream.
The Expo framework runs entirely on the end user's device. It's client-side software and I don't think MiTM attacks are the main part of the threat model. Like with most open source you may want to vet the supply chain and the code you include in your apps but Expo has been maintained for over seven years now and is generally trusted in this way in my experience.
We're building a universal app in Svelte, which makes Expo completely unusable. We've had to turn to capacitorjs.com instead, which is less mature but gets the job done.
I tried this a few weeks ago and their 'create-expo-app' package was broken because of incompatible dependencies. My project died before it could even start.
I use it to create very basic quality-of-life apps coded by ChatGPT. It's great, you can iterate very fast and immediately see the changes on your phone.
I see a lot of comments bashing cross platform mobile development. By and large, I agree but there is one very important caveat:
RN is amazing for the business, especially small businesses.
Yes it’s full of quirks and yes it’s never perfect but if you’re a small to medium size business trying to get your app to market as cheaply as possible, there is no better option than RN right now. Maybe flutter.
I've seen so many projects like this come and go. They go, in my opinion, for a reason: Web technologies just aren't great as an app platform.
If you want a web-like platform on which to build a cross-platform application, I recommend Flutter. It's not perfect but, it's better than all the other alternatives I've tried.
On the surface, yeah, but a bit deeper it allows a more web-style development flow; you as a developer only deal with the Javascript part, nothing about the native part. Expo is a runtime, whereas React Native / Metro is a full mobile app stack.
Likewise, with Expo it's easier to do code push, that is, just release a new JS bundle for over-the-air updates without going through the app store. Again, this is possible in RN as well, but it's a bit more involved.
Finally, Expo allows for easier (internal) demos; anyone with the Expo app installed can scan a QR code during your internal demo to install the app over the air, again without having to go through app stores. This can score you points depending on where you work.
Personally I'm still convinced 'real' native apps are better, but few companies want to invest in development & developers for that. My experience with React Native (not Expo) has been positive so far though, with very little issues between iOS and Android - actually, for me personally it's mainly been figuring out how to install custom fonts (custom fonts and Font Awesome for icons). I hope to not have to touch that again, lol.
I'm considering RN right now. Wondering whether to start from scratch or not. People refer to issues "ejecting" from Expo but those issues are vague and go back years.
Any concerns or experiences on your end that make it a good or bad option?
Ejecting is no longer required with EAS (Expo Application Services) build. You can bring in your own native dependencies and still use Expo without ejecting.
I use it for the Rust (video game) companion app, using the stock libraries bundled within Expo so development is a breeze.
IMO the best thing about expo is that your native project folders pretty much becomes build artifacts, and so can be left out of your git repo.
That is great because those project folders are usually quite fragile and can easily break over time.
Before "prebuild" was introduced, you had to stick to expo-included native modules to get that advantage, and if you didn't, you had to "eject", which was hardly better than not using expo at all.
With "prebuild" you can use any native module and still have a git repo free of those fragile iOS and Android folders. It is more work setting up those modules, but it's worth it IMO.
They like to do a lot of breaking changes between versions that are very painful to upgrade to. But this also applies to RN and JS ecosystem to a lesser extent.
I believe the situation with this has improved. Before EAS you needed to target one of the more recent SDK versions or you wouldn't be able to build using their services. However, if your app is new (or upgraded) enough to use EAS now then you don't get locked out of building anymore.
But still, upgrading SDK versions to stay on top of security/new features can be a burden with how many breaking changes there are.
It was our experience the expo layer added a lot of complexity and many bugs, with very little ability of users to actually fix anything without "ejecting" their project away from that ecosystem. That was on top of the RN layer, which in itself was full of bugs. We would send users to report expo bugs to the expo team, and were first met by "just fix it on your end, you are detox!" type of comments from that silly community, and those that did report the issues, saw no reaction from the expo team, despite detox being one of the most popular testing frameworks in the RN world at the time (no idea about now, but back then, even Facebook was using detox to test RN itself).
At the end of the day, we decided the hassle was not worth the low quality user benefit, so we decided to drop support for Expo. It was one of the best bureaucratic decisions we ever made.