Building a Mobile App with Expo, EAS, and React Native


It has never been easier for React developers to build native iOS and Android apps. In this talk, we'll see how quickly you can ship your app with Expo open source tools, Expo Application Services (EAS), and React Native. We'll also discuss some of the recent improvements we've made and what's coming up next.


Hey, everyone. My name is Brent. I'm an engineering manager at Expo. This talk is a high-level conceptual overview of building React Native apps with Expo and EAS. We're not going to talk about how to handle gestures and animations, navigation, or even talk through a single line of React Native code. There are some great resources for these topics that I'll link to at the end. This talk is more about process. If you want to build an app for Android and iOS and use React on the web, React Native is probably a good choice. A lot of the same knowledge will apply to React Native. The component API is the same. You can keep using your favorite state management library, React DevTools org, and a bunch of other stuff. Another thing React Native has in common with React DOM is that there's a small unopinionated core. A lot of the work that you need to do to build a web app exists outside of React DOM, and this is true to an even greater extent with React Native. React Native doesn't aim to provide an abstraction over everything that you need to do to build an app. What this means is that some familiarity with native code and tools will be needed. You'll have to learn a thing or two about Xcode and CocoaPods and Android Studio and Gradle. You'll need to be able to distinguish between a key store and a distribution certificate. Depending on what you're building, you might even need to get comfortable with writing native code. You can handle this in a few ways. You can grow the native skill set on your team of React developers. You can bring in native experts to manage the native side, and you can use Xcode tools. Xcode picks up where React Native leaves off and helps you stay productive in React. Xcode is a set of open source projects and hosted services to help you handle the accidental complexity of cross-platform app development. In the rest of this talk, we'll look at what Xcode can do, how its abstractions work, how these abstractions can sometimes fall short, and what we're doing to solve these limitations. So, I've said that Xcode picks up where React Native leaves off. Let me explain. Xcode makes it possible to write your app in just TypeScript or JavaScript and configure it in JSON. Notice the Android and iOS directories in the terminal on the left. To run this project, we'd open the Android and iOS project directories in Android Studio and Xcode, then compile and run the projects. But we don't have any native projects in the terminal on the right. It looks a lot more like a React DOM project. This is what an Xcode managed project looks like. To open it on Android or iOS, download an app from the app store called Xcode Go. This is an app that is like a web browser for developing React Native apps. Xcode Go includes a runtime with an extensive set of APIs built by the Xcode team to add capabilities like notifications and haptics. It also includes many of the most popular libraries in the React Native community and React Native itself. Let's think a minute to clarify what I mean by a runtime. In a web browser, the runtime includes the ECMAScript standard library along with standard web APIs. As a developer writing a website, you can't change it without sending a pull request to the browser engine. The runtime is controlled by the browser vendors. It includes all of the APIs that you can use from JavaScript. You might recognize these as the functions that stringify to native code in square brackets when you console log them. They expose access to DOM, the network, and other things like device location. In Node.js, you have the standard library from Node instead of the web APIs, and you can extend the runtime by building native extensions in languages like C++ or RAF. In a web browser, the runtime is provided by browser vendors. And in Xcode managed projects, the runtime is provided by Xcode. You can change it by sending a pull request to the Xcode repository on GitHub. In other React Native apps, for anything beyond React Native core APIs, you need to create or install native modules written in languages like Swift or Kotlin and recompile the app in order to use them from JavaScript. To install a library to an Xcode managed project, run Xcode install. Xcode install takes a version of the library that matches with the runtime version used by the project. We call the runtime version the Xcode SDK version. We can use the library from JavaScript without recompiling any native code. All these can preview your work in progress in Xcode Go. To do this, add your colleague to your team on the Xcode website, then publish your app with Xcode publish. Next, share the URL. You can set this up to run automatically on pull requests to get a preview workflow similar to what you can do on the web with services like Netlify and Vercel. You can also share code on Snack. Snack is a code sandbox type of environment that lets you edit and run code directly in a web browser. When you're ready to ship your app, run Xcode build Android or iOS. We call this build tool Turtle because it takes your app and packages it into a prebuilt shell app. The result is a standalone app, a binary that you can submit to a store. It's called a standalone app because it stands on its own. It's no longer dependent on Xcode Go to run. Here's how Turtle works. Build command uploads your app JavaScript bundle, manifests, and assets, like images and fonts. Then Turtle spins up a new worker and downloads the files that you just uploaded. It also downloads our prebuilt shell app. It then configures the shell app based off of properties in the manifest like the name and icon. It copies the downloaded JavaScript and assets into the shell app resources. And lastly, it signs the app with your app signing credentials. When this whole process is complete, we can go ahead and upload the standalone app to the source. To submit your app, run EAS submit dash P Android or iOS. Well, sort of. You'll actually have to submit your app through the Google Play console the first time you do it on Android because it's not yet possible through any public APIs. If you accidentally release your app with a bug, you can fix it locally and then run Expo publish to update JavaScript over the air. You can safely update Expo managed apps over the air because the code that you own is just JavaScript. So it's similar to updating a website. To update the app, we just download the new JavaScript and swap it in for the JavaScript bundle that's currently used in the shell. We usually do this when the app is restarted, but you can configure it differently if you want to. At a high level, that's how we ship a managed app with Expo and React Native today. Each week there are millions of people using apps built by tens of thousands of developers this way. Thousands of apps are built with Turtle for deployment to app stores each day. Now that we've seen the golden path, we can take a look at where these abstractions start to fall short. We get a lot of feature requests from developers building Expo managed apps, but we can distill most of them down to one of three things. First, I want to use a library that is not built into the Expo SDK. For example, React Native Web RPC. Second, I want to remove libraries that I'm not using. For example, to reduce the app size. And third, I want to include native code that I'm going to write myself and that isn't in any existing library. These three requests all point to one problem. A one size fits all Expo runtime doesn't actually fit all apps. People need to be able to customize the runtime in the React Native Android and iOS apps. Currently, if you get to the point where you need to modify the runtime, even if just to remove some code or add a single native module, you need to take control of your native projects. You can do this with Expo Eject. Expo Eject is a command that instantiates and configures the iOS and Android native project on your machine. You now have a standard native project and not just the JavaScript files. The name sounds very similar, but it's a bit different from create React app Eject because after running it, you're still using most Expo tools. That said, not everything is supported yet. Taking control of your native projects is a very reasonable solution for many developers and something that every Expo tool should support. Other developers prefer to have Expo continue to manage their native projects. They want to add and remove native libraries and let Expo take care of how that actually works. So, there are two parts to our solution to this problem. But you'll see soon that the first part is actually a prerequisite for the second. First, we need to make all Expo tools work in any React native project. And then we can make the native runtime customizable in managed projects. If we can make the runtime customizable, then developers can add or remove any native module in their managed projects. Most Expo tools already work outside of managed projects. For example, the Expo SDK packages like notifications and haptics. What we're missing is the Turtle build service and Expo Go. These tools were built specifically around a fixed runtime. So, we'll need to build new versions of these tools from scratch that can provide an equivalent experience. Turtle can't support any arbitrary React native app because it's purpose-built to assemble shell apps. This is very different from compiling an app. So, we built a new service from scratch called EAS Build. EAS stands for Expo Application Services. Running an Android or iOS build on some cloud server isn't exactly a novel idea, but we need to build it in order to provide a seamless and tailored experience, one that's deeply integrated with Expo services and React native. Here's how EAS Build works. You run EAS Build-P Android or iOS to create a shallow clone of your project's Git repo, compress it and upload it. EAS Build configures a new VM, then it downloads your project archive. It installs JavaScript dependencies and native dependencies, then kicks off a native build. When the build completes, it signs the resulting binary with your app sign-in credentials. Like most things in this talk, there's a bit more to it than that, but those are the high-level steps. Using EAS Build, we can now build and sign any React native project. The other missing piece is an equivalent to Expo Go. So, we've been building something we call Expo Development Client. It's a React native library that gives you the same experience as Expo Go, but with your own custom runtime. It's minimally opinionated to support the broadest set of use cases. When you create a debug build of your app, you get the development client experience. And when you create a release build, all of the development client code is stripped out. You can build the development client once and focus on the JavaScript side of your app, and then return to the development client when you want to write or install some new native code. So, with solutions for Turtle and Expo Go, we can move on to part two, customizing the runtime in managed Expo projects. In managed Expo projects, there are two places where we need to be able to modify the runtime, in our local development environment and in our standalone apps for distributing to stores. Let's start with standalone apps. We need a cloud build service capable of building projects with arbitrary native code. This sounds like a job for EAS Build. We can repurpose the eject command to generate and configure the native iOS and Android projects based on the JavaScript app. We'll call this new command prebuild. On EAS Build, we just need to run prebuild and build the resulting project like we would for any React Native app. There are no shell apps here. With this in place, developers can remove libraries they're not using because the prebuild command only links and configures libraries that are installed in the project. In simple cases, adding libraries will work fine, too, because React Native automatically links them through Gradle and Cocoa Puffs. But installing native module libraries often involves some additional configuration of native projects, and prebuild only knows how to do this for Expo SDK packages. We can solve this by giving developers hooks into the prebuild process and publicly documenting the tools we use to configure Expo SDK packages. We call these tools config plugins. Config plugins are functions that are executed during the prebuild process. They have access to utilities that make it easy to do the most common configuration tasks. And if those don't handle your use case, then you can directly access the project on the file system as an escape hatch. Developers can pass in options to config plugins like API keys and permission messages. Now that developers can customize their runtimes to add and remove libraries, if you happen to make some mistakes with over-the-air updates, you can end up in a situation where the JavaScript code for an update is incompatible with the runtime in the binary. We need to provide tools that make it easy to do the right thing in these scenarios. We won't go into that here, but it's worth noting that this is a new problem that arises with custom runtimes, and we're working on solutions in a new service called EAS Update. To customize the runtime in our development environment, we can use the Expo development client. Theoretically, and this isn't actually implemented yet at the time that I'm saying this, there are two steps to create a custom development client build for a managed project. First, install the development client packages in our managed project. Second, run a debug build of our project on EAS build. We can depend on the config plugins included in the development client packages to configure the client automatically during the pre-build phase. So that's it. Now it needs to be super easy to share your Expo development client builds. So we built something we call internal distribution into EAS build. You can use it to share development client builds with your friends and colleagues. To do this, first, if you're distributing to iOS, add the device to an allow list, so it'll be included in the provisioning profile. This isn't needed for Android. Now you can create a build. When the build completes, send the build URL to your colleague. They can install directly from that page. In the future, once all this is ready, building managed apps with Expo and React Native will look a lot more like this. You'll be able to install a native module library, then run a new development client build locally or on EAS build to add it to your development client runtime. Then you can just continue on building your app in TypeScript or JavaScript. EAS build and config plugins are available now. If Expo SDK 41 has been released by the time this talk airs, you can try EAS build with your SDK 41 project, and it should reduce your app size significantly by only including the native libraries that you're using. If you do, be careful when you're doing over-the-air updates. It's worth noting that EAS build is a paid service, and we plan to have a generous free tier, enough to support hobby developers, students, and small organizations that are just getting started. For now, EAS build is still in preview, and it's gated behind a paid plan. We'll be rolling out general availability in the summer. Expo development client and EAS update are both in closed data. If you're interested in trying them out, then follow the link on the screen to fill out a survey. If you're watching this a while after the recorded date, we'll keep those pages up to date so you can find relevant information there too. So, why are we doing this? Well, read Expo believe that a significant percentage of Android and iOS apps can be built with just TypeScript by using a development client with a custom runtime and leaning on the Expo SDK and React Native open source ecosystem. There are a lot of great libraries out there, and service providers are increasingly supporting React Native wrappers for their native packages. As React Native continues to mature, this will only get better and better. Even if you prefer to manage your native projects, these tools can enable better workloads for your team. They can help you to structure your process so that work on the runtime and application code are separate, similar to how building components with Storybook lets you split up your component system development from building features with those components. With that, you can get all the benefits that come along with having a stable runtime and a mechanism for loading apps into that runtime, like easy previews of pull requests on GitHub. We love the web and we want React Native to be more like it while still retaining what makes React Native great, and we think that the work that we've been doing is a big step in that direction. You can follow along on Twitter at Expo and not Brent, and we frequently post longer form updates to our blog. Learn how to get started in actually writing some code in React Native. Check out the learn links on the right-hand side. Thanks a lot for listening. Bye. Thank you so much for that wonderful talk. I hope you enjoyed it as much as I did. Brent is amazing. Now, before we go on, let's answer the question that Brent asked all of you. I hope you answered it in the Slido. So, Brent asked, what if you have ever shipped an app with React Native? And we can see that a good 30% of you folks have shipped an app with React Native. That's pretty impressive. And hopefully with some of the things that Brent talked about, you can even ship better apps with React Native coming up soon. So, I am going to invite Brent to join us on the stage. Brent, how are you doing? I'm pretty good. How are you? I'm good. Thank you. So, we've got quite a few questions coming in. Those of you, maybe, if you still got a question, make sure you drop it in the Discord chat. So, the first question, I'm just going to jump straight into it. From BKG, are there any downsides to using Expo, things it can't handle that you would need, that would make you need to eject from? Yeah, I think I tried to cover that a little bit in the talk in terms of mentioning the trade-offs that come with having a fixed runtime. And so, there's only so many things that we can really include inside of the preset, so fixed SDK runtime. And you can have a look at the feature requests page that Expo has to see some of the things that people run into. And there's some libraries in the React Native community that we don't include that a lot of people frequently would like to use. And so, a big part of what we're working on is addressing those limitations so that you can modify the runtime and you don't have to face those sort of trade-offs in terms of using the thing that you want to use while also getting the experience of having a lot of the complexity of managing your app kind of handled for you. Cool. Someone's asking a comparison question. So, they're asking, how does Expo compare to App Center Code Push? Does anyone have any experience? Is there any differences, anything similar? Yeah. So, I think the closest comparable there is Expo Updates, which is the over-the-air update service that I think is comparable to Code Push. They're pretty similar. I think Code Push has some interesting features that Expo doesn't have yet, and the same sort of thing goes the other way. I think there are a couple of things that arise just out of the fact that Expo Updates is integrated into Expo projects that make it maybe a little bit more convenient in some circumstances. But then in other circumstances, if you need to set them up from scratch, I think it's kind of a wash. But when you create a project with Expo CLI, you will get Expo Updates configured automatically for you. So, you don't have to do anything at all. You just have to create an account with Expo and you'll be able to publish updates to your app with Expo Publish. And so, it's all kind of set up. So, that's a really nice advantage that you get out of the box. And then there's another aspect of it where if you're using Expo Updates with this managed workflow that I mentioned a bit in the talk, where it's like we kind of manage the runtime for you, then you get really safe over-the-air updates because you don't have to be worried about the native code changing out under your feet in different circumstances. And so, if you publish a project for SDK 40 and then you go and make some changes to it and you publish again, that will work. Whereas you have to be a little bit more concerned when the runtime can change and like kind of have to be careful to ensure that the JavaScript that you're publishing is compatible. Thank you. Hopefully, that answers your question, Soroush. We have another question from Niz. Now, I don't know, I will admit that I don't know what these acronyms mean. So, if you do know what these acronyms mean, can you tell us? Will Expo ever support BLE directly or should we only rely on EAS? It's hard to say. We're not really focused on... I mean, this question is specifically about BLE, so that's Bluetooth Low Energy, but there are a lot of other potential APIs that people would say, oh, well, were you ever going to support this or this or this? And we could, like we kind of had a choice like, okay, are we going to go off and build all of these different API wrappers and support all of these indefinitely in the future and stick to this concept of like a managed runtime that just then grows and grows and grows. And so, that was one possible route we could have taken. And the other one was allow people to customize the runtime. And so, we've opted so far for like in the past year, let's focus on making the runtime customizable. And I think once we get that into a really good spot where people can use existing BLE libraries or whatever else they want to use in that purchase libraries, maps libraries, et cetera, that aren't included, then once that's sort of good, we can maybe circle back and be like, okay, well, which of these areas do you think we can actually have a positive impact on? There's no need to re-implement something that another library has already done an excellent job of. And so, if there's a really great BLE library out there and it makes sense for us to contribute to that, then we would do that. If it's something where we think, okay, well, maybe we need to rewrite this to make it like what we think it should be, then we would do that. And so, it's kind of on the table in terms of whether we integrate that or not. But most likely, I mean, the future of where development is going with Expo projects is definitely with EAS and things like the development client. Awesome. We've got another question just in from Rado. In order to add a library of, I think it's a clarification question, in order to add a library of native code, you need to eject, right? Yeah. So, at the moment, that's the case. So, that was kind of what I discussed in the first half of the talk was like, this is the fixed runtime. And then if you want to change that way that you do that now is you would eject and that would generate these native projects. And it's not quite the same as ejecting in Create React app where you eject and now it doesn't do anything for you anymore and you take on everything. It's kind of like halfway in between that and not ejecting. And so, basically, it generates the native projects that you would otherwise have managed for you and you can then add what you want to that. And that's kind of where it is now. And so, where we're going is the second half of the talk was what you would be able to do is add the library and then you'd be able to get EAS Build to do a new build of the client for you that includes that library. And then you could continue on with development as you were doing before. And so, that would allow you to kind of have that same managed workflow experience but still customize the runtime and add and remove libraries. So another thing is right towards the end of the talk, he said that there were some things which weren't that may not have been available yet that might be available now. Just out of curiosity, are they available now? So we did not release SDK 41 yet, but I will be doing that shortly after this. The stuff around like development client and so on, no, that's more of like a June, July sort of timeline for that. And yeah, so that's a little bit further out. Last week to this week, it's going to be, not much is going to change there. No worries. Maybe when someone's watching the recording, it would have been released by them. So a kind of question, you've been in the React Native space for a while. Just out of curiosity, what are your favorite React Native apps or maybe one that you've seen that you really liked? Well, I have to give a shout out to Coinbase because they're doing their IPO today. Coinbase Pro and some other stuff as well in React Native. And I think they did a good job with that. I really like this app called Readwise. You can go to It's a great tool for taking all of your sort of highlights from a bunch of different locations and actually reviewing them, not just like putting them into this like pile of like things that you like, hey, that's great. I want to remember this. I'm just going to like highlight it and then never think of it again. This thing will like connect to Kindle highlights and all your other Twitter or whatever and kind of use some space repetition reviewing. Also like the app called Third Wave. It's only usable in Canada right now, but it's really good coffee app. And just like some other like big ones like the PlayStation app, the new PlayStation app is really great. I just downloaded that. I didn't know it was built with React Native to be at the end. And of those are some of your React Native favorite apps. What about some of your favorite libraries? I'm going to have to definitely go with Gesture Handler and Reanimated as two of my favorites. Xcode GL is another really great one. It lets you use WebGL essentially or something close to that inside of React Native apps. And so you can use Three.js and things like that with it. And so, oh, actually, I forgot to mention another app I really like is Shop from Shopify. They use Xcode GL in their app and similar. Yeah, really cool uses of it. And of course, React Navigation library that I'm very much involved in, and that Xcode is I guess the lead kind of on the project for a number of years along with people like Satya, Satyajit Thakur, who's really been putting all of the work into that recently and making a great project with P5 and P6. Safe Area Context is another really great one from the guy that made Third Wave, Janik. I'm not even going to try saying his French last name. Sorry, Janik, if you're watching this. And that is a really fantastic way. I think if you're just joining React Native ecosystem now, it's easy to take for granted how easy it is to deal with safe areas on devices, whether that's the status bar or home indicator or notch or things like that. You just install React Native Safe Area Context and you have really nice idiomatic React APIs for dealing with these things. And it's fantastic. So yeah, I'd say those are my favorites. Nice. We've got another question coming in from Retrader. It's another general question. Where is React Native still lacking compared to native Android and iOS apps? Yeah. That's a good question. I think there are a few areas that kind of stand out. One that I really like to see is the ability to create rich text editors directly in React Native primitives. I think people tend to bridge a rich text editor or use a web view. I think it'd be really cool if we had just more rich primitives for doing this kind of thing and we're able to build that. And maybe with some of the improvements coming with fabric that could be possible. I think lists are another one. So things like flat lists and section lists, I think do a pretty good job, but it doesn't quite have the same performance characteristics as the built-in list views on either platform. And so it would be really neat to, when fabric again is released, to maybe see if that will unblock allowing us to use these same sort of view recycling APIs and get the same sort of performance characteristics. Awesome. And the last question, and I know this question actually, this question could be a whole nother talk. So I'm just going to ask you to kind of squeeze it into like the 30 seconds in this last question. What direction do you see Expo going in the next few years? What new features are in the long-term wish list beyond EAS? Well, EAS is potentially a very huge thing. It could encompass a broad set of services and ultimately giving people this ability to include any native module that they want is something that in the short, medium term, getting that down in a way that just works amazingly for everybody is going to be something that is going to be a challenge and that we're really looking forward to solving for people and think will have a great impact. But once we get that in place, there's a lot of integrations we can do with libraries and the ecosystem and the different services to ensure that you can just kind of plug them in and they just work out of the box. And whether that's tools like LogRocket or whatever kind of payments tool you're using or Maps tool, those sorts of things, it should be possible to just plug those into your app and get running. And so that's kind of where we're going there. And really the scope for the services we can offer through EAS are potentially pretty unbounded in terms of the areas of opportunity to improve the mobile development experience and cross-platform development experience. That's awesome. Thank you so much for hanging out with us, Brent. I really, really appreciate it. And where can people find you if they want to chat to you later? Twitter is probably a good spot. So, at notbrent on Twitter and I guess GitHub if you want to follow up activity on GitHub, Brent Batney on GitHub. Awesome. I love the username at notbrent. Thanks so much for hanging out with us. Bye. Thanks, bye. So those of you who are still sticking around, make sure you go over to the slider and give Brent's talk a big five star out of five. You can also join Brent in his speaker room on this spatial chat. The link to join is on the timeline. So definitely check that out if you have more questions for him. I just want to remind people, because I love prizes. I hope you love prizes. We have a raffle on Twitter. The way you enter this raffle is by taking a picture of your setup. I did it too. And tweeting it using the hashtag React Summit. Hopefully I win. Maybe I should get something free as an emcee. But hopefully I win as well. I just want it. Well, I will see you right after a short break. And we've got some more amazing talks lined up. See you soon.
36 min
14 May, 2021

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Workshops on related topic