Building and Deploying React Native Apps with Expo EAS
Building a React Native application with Expo is relatively straightforward. The workflow becomes more interesting when you're ready to turn that development project into an application that can actually be distributed to users.
This is where Expo Application Services (EAS) comes in.
EAS provides a set of tools for building, submitting, and updating Expo applications. Instead of manually managing native Android and iOS build environments, signing credentials, and distribution workflows, you can move much of that process into a repeatable CLI-based workflow.
In this guide, we'll walk through a practical Expo EAS workflow from development to production.
1. Start With an Expo Project
If you don't already have an Expo application, create one with:
npx create-expo-app@latest my-app
cd my-app
Start the development server:
npx expo start
At this stage, the application can be tested using Expo Go or a development build.
For larger applications, it's usually better to move toward development builds rather than relying entirely on Expo Go, especially when your application depends on native modules that aren't included in Expo Go.
2. Install EAS CLI
EAS is managed through the EAS CLI.
Install it globally:
npm install -g eas-cli
Then log in to your Expo account:
eas login
You can verify the installation with:
eas --version
3. Configure EAS
Inside your Expo project, initialize EAS:
eas build:configure
This creates an eas.json file.
A basic configuration might look like:
{
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal"
},
"production": {}
}
}
The three profiles serve different purposes.
Development
The development profile is intended for local development using an Expo development client.
eas build --profile development
Preview
The preview profile is useful when you want to distribute an installable build to testers without publishing it to the App Store or Google Play.
eas build --profile preview
Production
The production profile is used for your release builds.
eas build --profile production
Keeping these environments separate makes the deployment process much easier to manage.
4. Configure App Identifiers
Your Expo configuration needs unique identifiers for Android and iOS.
For example:
{
"expo": {
"name": "My App",
"slug": "my-app",
"version": "1.0.0",
"android": {
"package": "com.example.myapp"
},
"ios": {
"bundleIdentifier": "com.example.myapp"
}
}
}
The Android package and iOS bundleIdentifier identify your application on their respective platforms.
Choose these carefully because changing them later can effectively create a different application from the perspective of the app stores.
5. Build a Development Client
One of the most useful EAS features is the ability to create a custom development client.
Run:
eas build --profile development
You can specify a platform:
eas build --profile development --platform android
or:
eas build --profile development --platform ios
EAS handles the native build process remotely.
Once the build is installed on your device, start Metro with:
npx expo start --dev-client
Now you have a development environment that behaves much more like your eventual production application.
6. Create a Preview Build
Before releasing an application, it's useful to have a build that can be installed by testers.
That's where the preview profile is useful:
eas build --profile preview
For Android, this can produce an installable distribution build depending on your configuration.
A typical workflow might look like:
Development
↓
Development Build
↓
Feature Testing
↓
Preview Build
↓
QA / Internal Testing
↓
Production Build
This separation helps prevent unfinished code from accidentally reaching production.
7. Configure Environment Variables
Most production applications need different configuration for development and production.
For example:
API_URL
SUPABASE_URL
SUPABASE_ANON_KEY
EAS supports environment variables through EAS environments.
A common approach is to maintain separate environments:
development
preview
production
Then your application can use the appropriate values depending on the build profile.
For example:
eas env:list
You can also create environment variables through the EAS CLI.
Be careful with secrets. Variables bundled into a mobile application should not be treated as truly private because application binaries can be inspected.
Values such as public API endpoints or Supabase publishable/anonymous keys can generally be included in the client, while server-side secrets should remain on a backend.
8. Build for Production
Once the application has been tested, create a production build:
eas build --profile production
Or build for a specific platform:
eas build --profile production --platform android
eas build --profile production --platform ios
EAS handles the native compilation and signing workflow.
The result is a release-ready application binary that can be submitted to the appropriate app store.
9. Submit to Google Play and the App Store
EAS can also handle submission.
For Android:
eas submit --platform android
For iOS:
eas submit --platform ios
You can also combine building and submission into a single workflow:
eas build --platform android --profile production --auto-submit
and:
eas build --platform ios --profile production --auto-submit
The first submission still requires configuring the necessary Google Play and Apple credentials.
After that setup is complete, subsequent releases can be considerably simpler.
10. Automate the Workflow
Once your application has a stable release process, you can integrate EAS into CI/CD.
A typical pipeline might look like:
Git Push
↓
CI
↓
Install Dependencies
↓
Run Tests
↓
EAS Build
↓
Preview / Production
↓
EAS Submit
For example, you might configure your main branch so that a release tag triggers a production build.
This turns deployment from a manual process into something predictable and repeatable.
11. Use EAS Update for JavaScript Changes
One of the most useful features of the Expo ecosystem is EAS Update.
Not every change requires a new native application binary.
Changes to JavaScript, TypeScript, styling, and other compatible bundled assets can potentially be delivered through an over-the-air update.
For example:
eas update --channel production --message "Fix checkout button"
This can be much faster than creating a new App Store or Google Play release.
However, OTA updates do not replace native builds.
If you change something that affects the native runtime, such as adding or modifying a native module, you generally need to create a new application build.
A useful rule is:
JavaScript / compatible assets
↓
EAS Update
Native code / native dependencies
↓
EAS Build
12. A Practical Production Workflow
A simple workflow for an Expo application could be:
Local development
npm install
npx expo start
Development build
eas build --profile development
Internal testing
eas build --profile preview
Production release
eas build --profile production
Store submission
eas submit --platform android
eas submit --platform ios
JavaScript-only update
eas update --channel production --message "Bug fixes"
This gives the team a clear distinction between development, testing, native releases, and JavaScript updates.
Conclusion
Expo EAS makes the deployment side of React Native development significantly easier to manage.
Instead of treating Android and iOS deployment as completely separate processes, you can establish a consistent workflow:
Develop
↓
Development Build
↓
Preview
↓
Production Build
↓
App Store / Google Play
↓
EAS Update
The important part isn't simply knowing the EAS commands. It's establishing a predictable release process.
For a small project, that might mean manually running production builds when needed. For a larger application, the same workflow can evolve into a fully automated CI/CD pipeline.
Once EAS is configured correctly, deploying an Expo application becomes less about wrestling with native build tooling and more about shipping the application itself.