Have you ever wondered why web developers can push code changes and users see them instantlyâyet in mobile apps, even a tiny text fix can take days waiting for Apple or Googleâs approval? Every React Native developer has faced that frustration, especially when production bugs sneak in right after release.
Thatâs where Over-the-Air (OTA) updates come in. In simple terms, OTA updates let you deliver new JavaScript code, images, and other assets directly to usersâ devicesâwithout going through the app store review process. Itâs like refreshing a web page, but for your mobile app. With Expoâs EAS Updates, this process becomes seamless, secure, and fully integrated into your deployment workflow.
In this guide, youâll learn how to set up and use EAS Updates for your Expo React Native project, following a clear, step-by-step approach. By the end, youâll be able to ship updates instantly, fix issues in minutes, and make deployment virtually painless.
Prerequisites
Before diving in, make sure you have the following essentials ready:
- An Existing Expo Project: Your project must be configured to use EAS (Expo Application Services).
-
EAS CLI Installed: You need the EAS command-line tool.
npm install -g eas-cli -
An Initial Native Build: A crucial pointâOTA updates can only be pushed to an app that was originally built using
eas build. You must have a native binary (.ipaor.apk) installed on your test devices or available to your users. -
Expo Account: Logged in via the CLI (
eas login).
Step 1: Configure Your Project for Updates
EAS takes care of much of the heavy lifting, but we need to ensure the configuration is explicit, especially regarding channels. Channels are how you target updates to different environments (e.g., preview, development, production).
To initialize EAS Update configuration run
eas update:configure
This command will update your app.config.js (or app.json) file with the runtimeVersion and updates.url properties.
1.1 Configure the update channel
The channel property on a build allows you to point updates at specific types of builds. For example, it allows you to publish updates to a preview build without impacting your production deployment.
If you are using EAS Build, eas update:configure will set the update channel property on the preview and production profiles in eas.json. Set them manually if you use different profile names.
// eas.json
{
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"environment": "development",
"channel": "development"
},
"preview": {
"distribution": "internal",
"environment": "preview",
"channel": "preview"
},
"production": {
"environment": "production",
"channel": "production"
}
}
}
Step 2: Integrate expo-updates (Optional but Recommended)
While Expo handles automatic updates in the background, you might want to add a user interface (UI) to check for and apply updates immediately. This is particularly useful in development or for critical fixes.
2.1 Install the Module
If it’s not already installed, add the official updates module:
npx expo install expo-updates
2.2 Manually Check for Updates (Optional)
You can create a custom hook or function to check for updates when the app starts. This example shows how to use the useUpdates() hook in a functional component.
import { StatusBar } from 'expo-status-bar';
import * as Updates from 'expo-updates';
import { useEffect } from 'react';
import { Button, Text, View } from 'react-native';
export default function UpdatesDemo() {
const {
currentlyRunning,
isUpdateAvailable,
isUpdatePending
} = Updates.useUpdates();
useEffect(() => {
if (isUpdatePending) {
// Update has successfully downloaded; apply it now
Updates.reloadAsync();
}
}, [isUpdatePending]);
// If true, we show the button to download and run the update
const showDownloadButton = isUpdateAvailable;
// Show whether or not we are running embedded code or an update
const runTypeMessage = currentlyRunning.isEmbeddedLaunch
? 'This app is running from built-in code'
: 'This app is running an update';
return (
<View style={styles.container}>
<Text style={styles.headerText}>Updates Demo</Text>
<Text>{runTypeMessage}</Text>
<Button onPress={() => Updates.checkForUpdateAsync()} title="Check manually for updates" />
{showDownloadButton ? (
<Button onPress={() => Updates.fetchUpdateAsync()} title="Download and run update" />
) : null}
<StatusBar style="auto" />
</View>
);
}
Step 3: Build and Distribute the Native Container
Remember, OTA updates only change JavaScript and assets. If you change native code (e.g., add a new library or modify Podfile), you must create a new native build (.apk or .ipa).
Use the eas build command to create the initial app binary that contains the necessary update configuration.
# Build a preview binary for iOS
eas build --profile preview --platform ios
# Build a preview binary for Android
eas build --profile preview --platform android
Once this build is installed on the device, you are ready for the magic of instant updates.
Step 4: Publishing Your First OTA Update
Now for the moment of truth. You’ve fixed a typo, adjusted a style, or added a new feature that doesn’t involve native module changes.
Instead of running a full, time-consuming native build, you run a single command: eas update.
4.1 The Command
Use the --channel flag to target the specific channel defined in your eas.json (e.g., preview). remember will build for preview that is the reason where pushing to OTA to preview if you’re pushing for production you will use production
# Deploy a new update to all users with the preview binary installed on android
eas update --channel preview --platform android --message "Fixing that embarrassing typo on the homepage. đ
"
# Deploy a new update to all users with the production binary installed on ios
eas update --channel production --platform ios --message "Fixing that embarrassing typo on the homepage. đ
"
4.2 What Happens Next?
- Bundling: EAS bundles your latest JavaScript and static assets.
- Upload: The bundle is uploaded to the Expo CDN (Content Delivery Network).
- Assignment: The update is assigned to the specified branch (
previeworproduction). - Deployment: When a user opens their existing app, it checks the EAS Update server, downloads the new JavaScript bundle in the background, and applies it upon the next app restart or manually via your
expo-updatesimplementation.
Step 5: Testing the Deployed Update
To confirm your update works:
- Make a Visible Change: Change a simple
Textcomponent in your app (e.g., change “Welcome” to “Welcome Back!”). - Publish the Update: Run the
eas updatecommand from Step 4. - Test:
- Open your app on the device that has the native build from Step 3.
- Crucial: Close the app completely (kill it from the task switcher) and re-open it.
- You should see your new change instantly, without downloading anything from the App Store or installing !
Final Thoughts
Adopting EAS Updates transforms your deployment workflow. No longer are you beholden to slow review processes for minor fixes. You gain speed, agility, and a much better user experience by instantly delivering improvements.
While the freedom is great, remember: any change to native code still requires a full eas build and an App Store submission. For everything elseâJS, assets, business logicâeas update is your new best friend! Happy instant deploying! đ
