There's no need to install anything or even understand everything here, this page is meant to give you an overview of some of the big pieces of building a managed app. In the same way that getting a quick tour of Paris won't make you an expert on Paris, this walkthrough serves to help you identify a few landmarks and the most important areas in the managed workflow. You can do a walkthrough of the bare workflow
Let’s get started by initializing a project.
gives you several options for templates, including a TypeScript
template and one with React Navigation
installed and configured with a tab-based navigation structure.
Note: You may see several
peerDependencies warnings when installing the dependencies for a new project. These are caused by some external packages having overly strict or unnecessary dependencies, and it's a work in progress to clean them up. They won't cause any harm to your project.
Now we just run
yarn start (or
npm start if you prefer that package manager) in the project directory, which delegates to
expo start. You can also run
expo start if you prefer! It doesn't matter at all, pick one and go with it.
To run the app we don’t need to build any native code because it runs in the Expo Go
, and the CLI will automatically install it for us in the iOS simulator
or on any connected Android Emulator
or device. You can also download it from the App Store and Play Store.
If you close the
expo-cli or turn off your computer, you won't be able to access the app from your device anymore. We'll see how you can make it always available later on.
Let's scroll through the API Reference
to find packages that provide the capabilities that we need. If we know right away that the Expo SDK doesn’t have the necessary native APIs built-in, then we should probably eject or re-initialize with the bare workflow template.
Let's say we had mockups for our app that look like the following:
Note: These are actually screenshots from Sindre Sorhus' open source app Blear, but let's pretend they are mockups for the sake of demonstration.
We can tell from looking at the mockups that we’ll need a camera, access to permissions, some way to apply effects to an image, and a way to access the device media library to select images and to save images to an album. We can find equivalents for this by scrolling through the API reference.
We have to start somewhere so let’s start with the
ImagePicker. There’s a runnable example of it on the documentation page so let’s just copy that to get something running. Before pasting it into our app we will install all of the examples’ dependencies using
expo install is a wrapper around npm and yarn to ensure that the version of the Expo SDK and React Native community packages that you install are compatible with your app. When we paste the code in, the app will reload and we now have a working image picker.
At the risk of evoking the How To Draw an Owl meme
, let's jump right ahead to when the app is complete. To get from where we started to here you will need to read the React and React Native documentation as needed to build parts of your app, but that's too much to cover in this particular article. Find out about learning resources here
We can make a separate version of the app for web to just guide people to our app in the app stores, for when we have them up there. We can create a different entry point for the app by creating App.web.js and then build it there.
In a managed app we don’t have the native iOS or Android projects to poke around and modify, this is managed by Expo for us. So when we want to change configuration like the icon and splash screen image we can use app.json.
To share the app with teammates we can run
expo publish will upload your app artifacts to Expo's CDN (powered by CloudFront). If you would rather host everything on your own servers, read about how to do this in Hosting Updates on Your Servers.
You may have noticed that when we ran
expo publish the CLI warned us about optimizing assets. We can run
npx expo-optimize to do this, and it’ll make our assets a bit more lean if possible. Republish after this to reap the rewards.
Upon publishing you are given a persistent URL that you can share with colleagues, in this case it was https://expo.dev/@notbrent/blearexp
. This is determined by your Expo account username and the
field in your project app.json
On iOS, only you can open projects that you have built unless you have a priority plan
, in which case your teammates can open your projects as well.
Now when we run
it will kick off a build with the Expo build service. We will be prompted to enter our Apple Developer credentials, and then we’ll just hit enter a couple of times to let Expo handle the distribution certificate, push key, and provisioning profile. You can also provide all of this yourself, which you might want to do if you are moving an existing app to the managed workflow. (Concerned about security?
expo build:[ios/android] uses the Expo build service — if you would rather run builds on your own infrastructure, read about how to do this in Building Standalone Apps on Your CI
Now you can use Transporter
to upload the app to App Store Connect, but we find that it’s a bit easier to run
instead. Once it's up on App Store Connect, you'll have to do some manual work within their web interface. Read more about deploying to app stores
Android builds follow a similar process to iOS builds, but we are going to restrict the permissions that we need here to just the ones we use in the app because Android permissions are more static than iOS. The Android equivalent of iOS'
We’ll build an Android App Bundle (.aab)
here because we want a more lean binary for the Play Store, but if you want to install the binary on a local device for testing, leave out the
flag and you’ll get a .apk
Now we need to create the app in the Google Play Console and upload it through the web interface manually. After the first time you have uploaded the app, subsequent uploads can be done with
. Read more about deploying to app stores
expo build:web then upload the
web-build directory to any host capable of serving static files.
Once your app is out for testing or on the stores you probably don’t want to have to repeat the process again to make some small changes. In this case, we noticed that we weren’t asking for camera roll permissions before saving the image, so if you tried to save an image before picking one from the camera roll then it wouldn’t work. To ship an update, we just need to run
expo publish again.
When we built our Android app bundle above, we told it to point to a specific Android release channel (learn more about release channels
). To publish an update to the Android app we then need to update that release channel too.
We frequently release updates to the Expo SDK
. If you decide to update your app to a newer version of our SDK, copies of the older version will continue to work fine. Users will download the newest copy that their client supports.
An in-depth guide
to setting up push notifications end-to-end from your app to server is a good place to look for more information here. To quickly demonstrate how easy it is to get something simple wired up, without introducing any complexity of a server, take a look at how we can test out notifications using the Push notifications tool
You are now, at a very high level, familiar with the steps you would go through to create an app with the Expo managed workflow.