Configuring Over-the-Air Updates in React Native with Expo Updates
Ever wished you could update your app’s features or fix bugs without waiting for app store approvals? With over-the-air (OTA) updates, you can! OTA updates let you push new JavaScript code and assets directly to your React Native app, so users get the latest changes instantly.
In this friendly guide, we’ll walk you through setting up OTA updates using Expo Updates with Expo SDK 51, which works beautifully with React Native 0.75.4. Whether you’re new to React Native or just curious about OTA, this tutorial has you covered—no prior experience needed. Want a head start? Check out prebuilt templates with OTA support at Instamobile or Dopebase.
By the end, you’ll have a React Native app ready to roll out updates seamlessly to iOS and Android users, with separate setups for staging and production environments. Let’s dive in!
Prerequisites
Before we get started, make sure you have these tools ready:
- Node.js (v20.x or later, LTS recommended): Grab it from nodejs.org.
- npm (v10.x or later, comes with Node.js).
- Expo CLI: Our go-to for easy React Native setup.
- Android Studio (2024.3.2 or later): For Android development, with Android SDK 35 and NDK r25+.
- Xcode (16+): For iOS development (macOS only). You’ll need Xcode 16+ (iOS 18 SDK) to meet App Store requirements.
- A code editor like VS Code.
- Git: For version control and managing your code.
Got everything? Awesome—let’s set up your project!
Step 1: Create Your React Native Project
Let’s kick things off by setting up a fresh React Native project with Expo.
-
Install Expo CLI globally to make project setup a breeze:
npm install -g expo-cli
-
Create a new project called
MyApp
:expo init MyApp
Choose the blank (TypeScript) template for a modern, type-safe setup. Expo SDK 51 powers this project, working smoothly with React Native 0.75.4.
-
Navigate to your project folder:
cd MyApp
-
Add the
expo-updates
package for OTA magic:npm install [email protected]
-
Test your setup to make sure everything’s working:
npx expo start
Press
a
for Android ori
for iOS (macOS only) to launch the app on an emulator or device. You should see a simple welcome screen.
Summary: You’ve set up a new React Native project with Expo SDK 51 and added expo-updates
to enable OTA updates.
Mega Bundle Sale is ON! Get ALL of our React Native codebases at 90% OFF discount 🔥
Get the Mega BundleStep 2: Set Up Expo Updates
Now that your project is ready, let’s configure Expo Updates to handle OTA updates. This step connects your app to Expo’s cloud service, so you can push updates directly to users.
Project Configuration
-
Update
app.json
to enable OTA updates:{
"expo": {
"updates": {
"enabled": true,
"url": "https://u.expo.dev/your-project-id",
"checkAutomatically": "ON_LOAD",
"fallbackToCacheTimeout": 0
},
"ios": {
"bundleIdentifier": "com.myapp.app"
},
"android": {
"package": "com.myapp.app"
}
}
}You’ll get your
project-id
in Step 3 when we set up EAS (Expo Application Services). -
For bare workflows, link
expo-updates
:- iOS: Run
npx pod-install
to set up CocoaPods dependencies. - Android: Add the following to
android/app/build.gradle
:apply from: "../../node_modules/expo-updates/expo-updates.gradle"
- iOS: Run
-
Add update-checking logic to
src/App.tsx
:import { useEffect } from 'react';
import { View, Text } from 'react-native';
import * as Updates from 'expo-updates';
export default function App() {
useEffect(() => {
const checkForUpdates = async () => {
try {
const update = await Updates.checkForUpdateAsync();
if (update.isAvailable) {
await Updates.fetchUpdateAsync();
await Updates.reloadAsync();
}
} catch (e) {
console.error('Update check failed:', e);
}
};
checkForUpdates();
}, []);
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Welcome to MyApp!</Text>
</View>
);
}This code checks for new updates when the app starts, downloads them, and reloads the app to apply them.
iOS Configuration
- Open
ios/MyApp.xcworkspace
in Xcode and confirmExpoUpdates
is linked in the Pods target. - Add the
EXUpdatesURL
key toInfo.plist
with the valuehttps://u.expo.dev/your-project-id
. - Ensure the app’s bundle identifier matches
app.json
.
Android Configuration
- Update
android/app/src/main/res/values/strings.xml
:<resources>
<string name="expo_updates_url">https://u.expo.dev/your-project-id</string>
</resources> - Ensure
MainApplication.java
includesexpo-updates
:import expo.modules.updates.UpdatesPackage;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected List<ReactPackage> getPackages() {
return Arrays.asList(
new MainReactPackage(),
new UpdatesPackage()
);
}
};
}
Summary: You’ve configured Expo Updates in your app, setting up the foundation for OTA updates. Next, we’ll connect to EAS to manage those updates.
Step 3: Connect to EAS for OTA Updates
With your app configured, let’s hook it up to Expo Application Services (EAS), the cloud platform that powers OTA updates by hosting your JavaScript bundles.
-
Log in to Expo:
eas login
Follow the browser prompt to authenticate your account.
-
Set up EAS for your project:
eas build:configure
This creates an
eas.json
file:{
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal"
},
"production": {}
}
} -
Initialize OTA updates:
eas update:configure
This generates a project ID, which you’ll add to
app.json
underupdates.url
. -
Build your app to test OTA compatibility:
eas build --profile preview --platform all
This creates iOS and Android binaries ready for OTA updates.
Summary: You’ve connected your app to EAS, setting up the cloud infrastructure to deliver OTA updates. Now, let’s try pushing your first update!
Step 4: Deploy Your First OTA Update
Now that your app is linked to EAS, let’s deploy an update to see OTA in action.
-
Make a small tweak to your app, like updating the welcome message in
src/App.tsx
:<Text>Welcome to MyApp! (Updated)</Text>
-
Publish the update to the production branch:
eas update --branch production
This uploads your new JavaScript bundle to EAS.
-
Test the update:
- Run your app in preview or production mode (avoid Expo Go, as it may interfere with updates).
- Close and reopen the app to download the update.
- Check that the updated message appears.
-
For a staging environment, publish to a separate branch:
eas update --branch staging
Use the EAS dashboard to manage branches or roll back updates if needed.
Summary: You’ve successfully deployed an OTA update, and your app now reflects the latest changes without an app store submission.
Step 5: Set Up Staging and Production Environments
To keep things organized, let’s configure separate OTA updates for staging and production environments, so you can test changes safely before going live.
-
Create a dynamic
app.config.ts
for environment-specific settings:import { ConfigContext, ExpoConfig } from 'expo/config';
export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
name: process.env.APP_ENV === 'staging' ? 'MyApp Staging' : 'MyApp',
slug: 'myapp',
updates: {
enabled: true,
url: `https://u.expo.dev/your-project-id`,
checkAutomatically: 'ON_LOAD',
fallbackToCacheTimeout: 0,
},
ios: {
bundleIdentifier: process.env.APP_ENV === 'staging' ? 'com.myapp.staging' : 'com.myapp.app',
},
android: {
package: process.env.APP_ENV === 'staging' ? 'com.myapp.staging' : 'com.myapp.app',
},
}); -
Build for each environment:
- Staging:
eas build --profile preview --platform all
- Production:
eas build --profile production --platform all
- Staging:
-
Publish updates for each environment:
APP_ENV=staging eas update --branch staging
APP_ENV=production eas update --branch production -
Test the environments:
- Install the staging build and verify the staging branch updates.
- Install the production build and confirm the production branch updates.
Summary: You’ve set up separate staging and production environments, allowing safe testing of updates before they reach all users.
Step 6: Enhance Your OTA Workflow
With your OTA system up and running, let’s explore ways to make it even better.
- Rollbacks: If an update goes wrong, revert it using the EAS dashboard or CLI:
eas update:rollback --branch production
- A/B Testing: Create branches like
experiment-a
andexperiment-b
to test new features with different user groups. - Analytics: Add
expo-analytics
to track how users interact with updates and catch errors early. - Optimize Updates: Keep update sizes small by excluding unused assets and using code-splitting techniques.
Summary: Enhance your OTA setup with rollbacks, A/B testing, analytics, and optimization for a smooth and reliable update process.
Troubleshooting Tips
- Updates Not Loading: Ensure you’re not in debug mode, as it skips OTA updates. Test with preview or production builds.
- iOS Issues: Verify the
EXUpdatesURL
inInfo.plist
matches your EAS project ID. - Android Problems: Check
expo-updates
linking inandroid/app/build.gradle
and confirmexpo_updates_url
is set instrings.xml
. - EAS Setup Errors: If
eas update:configure
fails, manually checkeas.json
and your project ID.
Looking for a custom mobile application?
Our team of expert mobile developers can help you build a custom mobile app that meets your specific needs.
Get in TouchConclusion
You’ve built a React Native app with OTA updates using Expo Updates and Expo SDK 51, making it easy to push new features and fixes to iOS and Android users instantly. With separate staging and production environments, you’re ready to test and deploy like a pro. Want to speed things up? Explore prebuilt templates with OTA support at Instamobile or Dopebase. For more advanced features, check out Expo’s documentation or join the React Native community at reactnative.dev.
Additional Resources
- dopebase.com - Mobile app development resources and templates
- instamobile.io - Production-ready React Native templates
- instaflutter.com - Flutter templates for cross-platform development
- reactnative.dev - Official React Native documentation
- docs.expo.dev - Expo SDK and EAS documentation