TL;DR: OTA updates are enforced by default. App Store updates can be enforced by adding code to check your app version on startup and, if there's a new version, open the App Store on your app's page.

There's two ways of updating a standalone Expo app:

  1. OTA update using expo-cli publish
  2. Using Google Play/App Store

Both of these methods have advantages and shortcomings.

OTA Updates

This is the usual way an update is delivered to Expo apps. OTAs are done via the expo CLI tool and deliver new Javascript code based on your package.json settings. This option also offers the option to publish code using release channels, meaning you could push updates first to you staging environment, validate the update and then push it to production via CLI like so:

expo-cli publish -release-channel staging # pushes and update to the staging channel
expo-cli publish -release-channel production # pushes an update to the production channel

If you are publishing but your standalone app is not updating you might be pushing code to the wrong release channel. You can read more about release channels here.

OTAs are enforced by default:

By default, Expo will check for updates automatically when your app is launched and will try to fetch the latest published version. If a new bundle is available, Expo will attempt to download it before launching the experience.

However it's possible to disable this behavior by setting updates.enabled to false in app.json and then implement your own logic (or none at all), as per the example in their docs:

try {
  const update = await Expo.Updates.checkForUpdateAsync();
  if (update.isAvailable) {
    await Expo.Updates.fetchUpdateAsync();
    // ... notify user of update ...
    Expo.Updates.reloadFromCache();
  }
} catch (e) {
  // handle or log error
}

This system is really great for pushing new JS code to your users, it really helps with live testing since you can test your app with your user, find a flaw, fix it and publish new code which will be almost instantly available for download.

Yet this method has its limitations, for example: you can't update the Expo SDK version this way, you must build a new standalone app and distribute it through the app store (or whatever other method of your choosing).

App Stores

This is the most common way to distribute your .apk and .ipa files. These files can be created by using the expo-cli build:android and expo-cli build:ios for Android and iOS respectively.

It seems like there's an Android API being tested to enforce apps to be updated via this method (SO thread, article), but I don't think it's available yet.

One possible solution to enforce updates via this method is to check your app version on startup and, if there's a new version available in the store, open the app's store page via deep linking so the user is able download it. The example below should help you visualize what I mean.

componentDidMount {
   const hasNewVersion = isStoreUpdateAvailable(); // Checks the store for a new app update
   if (hasNewVersion) {
     Linking.openURL("market://details?id=<>"); // Opens the app's store page so the user can download the update
   }
}

Here's the docs about linking to Google Play.

Hope this answers all your questions, if not leave a comment and I'll edit the answer.

Answer from Bruno Eduardo on Stack Overflow
🌐
GitHub
github.com › SohelIslamImran › expo-in-app-updates
GitHub - SohelIslamImran/expo-in-app-updates: A lightweight and easy-to-use module for implementing native in-app updates for Android and iOS
A lightweight and easy-to-use module for implementing native in-app updates for Android and iOS - SohelIslamImran/expo-in-app-updates
Starred by 246 users
Forked by 11 users
Languages   TypeScript 36.6% | Kotlin 28.6% | Swift 24.5% | JavaScript 7.0% | Ruby 3.3%
🌐
Expo Documentation
docs.expo.dev › versions › latest › sdk › updates
Updates - Expo Documentation
The expo-updates library can be automatically configured using EAS Update, which is a hosted service that manages and serves updates to your app. To get started with EAS Update, follow the instructions in the Get started guide.
🌐
Expo Documentation
docs.expo.dev › eas-update › download-updates
Downloading updates - Expo Documentation
You can check for updates at various points in your app's lifecycle, such as when it is foregrounded or at some interval. When an update is found, you may want to show a dialog to the user to prompt the user to update. You can check for updates at launch and display your own custom loading screen, if it is very important for your use case to ensure that users always get the latest version at launch. You can use expo...
Top answer
1 of 3
30

TL;DR: OTA updates are enforced by default. App Store updates can be enforced by adding code to check your app version on startup and, if there's a new version, open the App Store on your app's page.

There's two ways of updating a standalone Expo app:

  1. OTA update using expo-cli publish
  2. Using Google Play/App Store

Both of these methods have advantages and shortcomings.

OTA Updates

This is the usual way an update is delivered to Expo apps. OTAs are done via the expo CLI tool and deliver new Javascript code based on your package.json settings. This option also offers the option to publish code using release channels, meaning you could push updates first to you staging environment, validate the update and then push it to production via CLI like so:

expo-cli publish -release-channel staging # pushes and update to the staging channel
expo-cli publish -release-channel production # pushes an update to the production channel

If you are publishing but your standalone app is not updating you might be pushing code to the wrong release channel. You can read more about release channels here.

OTAs are enforced by default:

By default, Expo will check for updates automatically when your app is launched and will try to fetch the latest published version. If a new bundle is available, Expo will attempt to download it before launching the experience.

However it's possible to disable this behavior by setting updates.enabled to false in app.json and then implement your own logic (or none at all), as per the example in their docs:

try {
  const update = await Expo.Updates.checkForUpdateAsync();
  if (update.isAvailable) {
    await Expo.Updates.fetchUpdateAsync();
    // ... notify user of update ...
    Expo.Updates.reloadFromCache();
  }
} catch (e) {
  // handle or log error
}

This system is really great for pushing new JS code to your users, it really helps with live testing since you can test your app with your user, find a flaw, fix it and publish new code which will be almost instantly available for download.

Yet this method has its limitations, for example: you can't update the Expo SDK version this way, you must build a new standalone app and distribute it through the app store (or whatever other method of your choosing).

App Stores

This is the most common way to distribute your .apk and .ipa files. These files can be created by using the expo-cli build:android and expo-cli build:ios for Android and iOS respectively.

It seems like there's an Android API being tested to enforce apps to be updated via this method (SO thread, article), but I don't think it's available yet.

One possible solution to enforce updates via this method is to check your app version on startup and, if there's a new version available in the store, open the app's store page via deep linking so the user is able download it. The example below should help you visualize what I mean.

componentDidMount {
   const hasNewVersion = isStoreUpdateAvailable(); // Checks the store for a new app update
   if (hasNewVersion) {
     Linking.openURL("market://details?id=<>"); // Opens the app's store page so the user can download the update
   }
}

Here's the docs about linking to Google Play.

Hope this answers all your questions, if not leave a comment and I'll edit the answer.

2 of 3
14

UPDATED ANSWER

Since the accepted answer was posted, Expo made changes to the Updates API.

Here's the breaking change.

Updates.reloadFromCache has been renamed to Updates.reloadAsync, and Updates.reload has been removed.

  import * as Updates from 'expo-updates' // Updates*

  try {
    const update = await Updates.checkForUpdateAsync()
    if (update.isAvailable) {
      await Updates.fetchUpdateAsync()
      // NOTIFY USER HERE
      Updates.reloadAsync()
    }
  } catch (e) {
      // HANDLE ERROR HERE
  }

For those wondering where to run this code, I advise to insert it in the componentDidMount/useEffect() method.

🌐
Expo Documentation
docs.expo.dev › bare › installing-updates
Install expo-updates in an existing React Native project - Expo Documentation
... expo-updates is a library that enables your app to manage remote updates to your application code. It communicates with the configured remote update service to get information about available updates.
🌐
npm
npmjs.com › package › expo-updates
expo-updates - npm
The expo-updates module enables your app to manage remote updates to your application code. This module works with a server that implements the Expo Update protocol. The EAS Update hosted service implements this protocol.
      » npm install expo-updates
    
Published   Dec 08, 2025
Version   29.0.15
Author   650 Industries, Inc.
🌐
Expo Documentation
docs.expo.dev › eas-update › introduction
EAS Update - Expo Documentation
It accomplishes this by enabling an app to update its own non-native pieces (such as JS, styling, and images) over-the-air. All apps that include the expo-updates library have the ability to receive updates.
🌐
npm
npmjs.com › package › expo-in-app-updates
expo-in-app-updates - npm
Native in-app updates for Android and iOS. Latest version: 0.9.0, last published: a year ago. Start using expo-in-app-updates in your project by running `npm i expo-in-app-updates`. There are no other projects in the npm registry using expo-in-app-updates.
      » npm install expo-in-app-updates
    
Published   Feb 06, 2025
Version   0.9.0
Author   SohelIslamImran
Find elsewhere
🌐
Reddit
reddit.com › r/reactnative › need help with forcing app updates in expo-managed react native app.
r/reactnative on Reddit: Need Help with Forcing App Updates in Expo-Managed React Native App.
January 17, 2024 -

Hi everyone at r/reactnative

I'm currently working on a React Native project using Expo and facing a challenge that I hope to get some insights on from this amazing community.

Issue: I need to ensure that users are always using the latest version of my app. Is there a way to force or prompt users to update the app when a new version is released, specifically in an Expo-managed workflow?

What I've Tried:

  • I've looked into the Expo documentation but couldn't find a straightforward method to implement this.

  • I've also considered using some third-party libraries, but I'm unsure about their compatibility with Expo.

Questions:

  1. Has anyone here implemented a similar feature in their Expo-managed React Native app?

  2. What are the best practices or tools to use for this purpose?

  3. Are there any specific challenges I should be aware of?

Any guidance, code snippets, or resource links would be greatly appreciated. I'm particularly interested in solutions that are tested and known to work well within the Expo framework.

Thank you in advance for your help!

🌐
Expo Documentation
docs.expo.dev › eas-update › integration-in-existing-native-apps
Using EAS Update in an existing native app - Expo Documentation
Learn how to integrate EAS Update into your existing native Android and iOS app to enable over-the-air updates.
🌐
Josiah
imighty.hashnode.dev › simplifying-react-native-app-updates-with-expo-eas-and-in-app-updates
Expo EAS, OTA, and In-App Updates
November 6, 2023 - In React Native, managing updates from both the app stores (Google Play and App Store) and Over-The-Air updates through Expo's EAS (Expo Application Services) can be streamlined with the help of the expo-updates library and the sp-react-native-in-app-update library.
🌐
Medium
medium.com › @caleb_23647 › expo-updates-fa846ce96640
Expo Updates. Hey React Native Expo developers! Have… | by Purple Wren Digital | Medium
November 30, 2023 - Expo Updates is a library from Expo that allows developers to instantly push app updates and changes to their in-testing (think TestFlight) or in-production app. It’s a part of the Expo ecosystem, which simplifies the React Native development ...
🌐
CodeMiner42
blog.codeminer42.com › home › react › how to speed up mobile app development with expo ota updates
How to Speed Up Mobile App Development with Expo OTA Updates - The Miners
July 7, 2025 - OTA update, or Over-The-Air update is a method to push code updates to users without the need of creating new builds. In this article, I will be referring to the Expo solution for OTA updates, the EAS update. OTA updates can be used to push changes to the Javascript part of the app and these updates are auto-downloaded by the builds when users start the app.
🌐
Expo Documentation
docs.expo.dev › workflow › upgrading-expo-sdk-walkthrough
Upgrade Expo SDK - Expo Documentation
Learn how to incrementally upgrade the Expo SDK version in your project. ... We recommend upgrading SDK versions incrementally, one at a time. Doing so will help you pinpoint breakages and issues that arise during the upgrade process. With a new SDK release, the latest version enters the current release status. This applies to Expo Go as it only supports the latest SDK version and previous versions are no longer supported.
🌐
Expo Documentation
docs.expo.dev › bare › updating-your-app
Get started with EAS Update - Expo Documentation
If you are already signed in to an Expo account using Expo CLI, you can skip the steps described in this section. If you are not, run the following command to log in: ... You can check whether you are logged in by running eas whoami. ... The eas update:configure command will update your app.json file with the runtimeVersion and updates.url properties, and add the extra.eas.projectId field if your project wasn't using any EAS services previously.
🌐
GitHub
github.com › expo › UpdatesAPIDemo
GitHub - expo/UpdatesAPIDemo: Demo app showing the useUpdates() API
In the simulator, navigate back to the home screen, and then click on the app icon to bring it back to the foreground. The monitor code will check the update server and show that a new update is available. Force quit the app, and then issue a yarn update command like the one above, to run EAS Update again and upload a new update bundle to the server. Now start the app. Since the expo-updates module has the default configuration for automatic updates, it will query the server on startup, see that there is an update, and download it.
Starred by 78 users
Forked by 7 users
Languages   TypeScript 88.2% | JavaScript 5.4% | EJS 3.7% | Shell 2.7%
🌐
Expo
expo.dev › changelog
Changelog — Expo
Check out new updates and improvements to Expo and EAS from the Expo team.
🌐
Expo
expo.dev › blog › eas-update-best-practices
Streamline your mobile app deployment using these EAS Update best practices
Explore best practices for using EAS Update to accelerate delivery, reduce release overhead, and improve how quickly your users get updates.
🌐
Medium
shift.infinite.red › how-to-implement-over-the-air-updates-with-expo-updates-in-react-native-c26787d4a3cf
How to implement over the air updates with expo-updates in React Native | by Jamon Holmgren | Red Shift
September 20, 2021 - This allows Expo to host my JS bundle and lets expo-updates retrieve any updated bundles from their servers. I took note of my username (jamonholmgren) and the project slug (OTAHack), as we’ll be setting those in two places below. When Ignite was finished and I had a newly minted app, I cd ’d into that directory and installed expo-updates from the command line.