A library that allows programmatically controlling and responding to new updates made available to your app.
The expo-updates
library allows you to programmatically control and respond to new updates made available to your app.
Android Device | Android Emulator | iOS Device | iOS Simulator | Web |
---|---|---|---|---|
-
npx expo install expo-updates
If you're installing this in a bare React Native app, you should also follow these additional installation instructions.
Learn how to configure the native projects in the installation instructions in the expo-updates
repository.
Most of the methods and constants in this module can only be used or tested in release mode. In debug builds, the default behavior is to always load the latest JavaScript from a development server. It is possible to build a debug version of your app with the same updates behavior as a release build. Such an app will not open the latest JavaScript from your development server — it will load published updates just as a release build does. This may be useful for debugging the behavior of your app when it is not connected to a development server.
To test manual updates in the Expo Go app, run eas update
and then open the published version of your app with Expo Go.
To test manual updates with standalone apps, you can create a .apk or a simulator build, or make a release build locally with npx expo run:android --variant release
and npx expo run:ios --configuration Release
(you don't need to submit this build to the store to test).
The expo-updates
library exports a variety of functions to interact with updates once the app is already running. In some scenarios, you may want to check if updates are available or not. This can be done manually by using checkForUpdateAsync()
as shown in the example below:
import { View, Button } from 'react-native';
import * as Updates from 'expo-updates';
function App() {
async function onFetchUpdateAsync() {
try {
const update = await Updates.checkForUpdateAsync();
if (update.isAvailable) {
await Updates.fetchUpdateAsync();
await Updates.reloadAsync();
}
} catch (error) {
// You can also add an alert() to see the error message in case of an error when fetching updates.
alert(`Error fetching latest Expo update: ${error}`);
}
}
return (
<View>
<Button title="Fetch update" onPress={onFetchUpdateAsync} />
</View>
);
}
expo-updates
with a custom serverEvery custom updates server must implement the Expo Updates protocol.
You can find an example implementation of a custom server and an app using that server in this GitHub repository.
There are build-time configuration options that control the behavior of expo-updates
.
On Android, these options are set as meta-data
tags adjacent to the tags added during installation in the AndroidManifest.xml file. You can also define these options at runtime by passing a Map
as the second parameter of UpdatesController.overrideConfiguration()
, and the provided values will override any value specified in AndroidManifest.xml.
On iOS, these properties are set as keys in the Expo.plist file. You can also set them at runtime by calling [EXUpdatesAppController overrideConfigurationWithConfiguration:]
at any point before expo-updates
is initialized, and the values in this dictionary will override any values specified in Expo.plist. If you tried to use the EXUpdatesAppController
from the AppDelegate.mm, you will need to add the following imports:
#import "ExpoModulesCore-Swift.h"
#import "EXUpdatesInterface-Swift.h"
#import "EXUpdates-Swift.h"
iOS plist/dictionary key | Android Map key | Android meta-data name | Default | Required? |
---|---|---|---|---|
EXUpdatesEnabled | enabled | expo.modules.updates.ENABLED | true | |
EXUpdatesURL | updateUrl | expo.modules.updates.EXPO_UPDATE_URL | (none) | |
EXUpdatesRequestHeaders | requestHeaders | expo.modules.updates.UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY | (none) | |
EXUpdatesSDKVersion | sdkVersion | expo.modules.updates.EXPO_SDK_VERSION | (none) | (exactly one of sdkVersion or runtimeVersion is required, Required for apps hosted on Expo's server) |
EXUpdatesRuntimeVersion | runtimeVersion | expo.modules.updates.EXPO_RUNTIME_VERSION | (none) | (exactly one of sdkVersion or runtimeVersion is required) |
EXUpdatesReleaseChannel | releaseChannel | expo.modules.updates.EXPO_RELEASE_CHANNEL | default | |
EXUpdatesCheckOnLaunch | checkOnLaunch | expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH | ALWAYS (ALWAYS , NEVER , WIFI_ONLY , ERROR_RECOVERY_ONLY ) | |
EXUpdatesLaunchWaitMs | launchWaitMs | expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS | 0 | |
EXUpdatesCodeSigningCertificate | codeSigningCertificate | expo.modules.updates.CODE_SIGNING_CERTIFICATE | (none) | |
EXUpdatesCodeSigningMetadata | codeSigningMetadata | expo.modules.updates.CODE_SIGNING_METADATA | (none) | |
EXUpdatesCodeSigningIncludeManifestResponseCertificateChain | codeSigningIncludeManifestResponseCertificateChain | expo.modules.updates.CODE_SIGNING_INCLUDE_MANIFEST_RESPONSE_CERTIFICATE_CHAIN | false | |
EXUpdatesConfigCodeSigningAllowUnsignedManifests | codeSigningAllowUnsignedManifests | expo.modules.updates.CODE_SIGNING_ALLOW_UNSIGNED_MANIFESTS | false |
For a detailed explanation, see the expo-updates
repository.
import * as Updates from 'expo-updates';
Updates.channel
Type: string | null
The channel name of the current build, if configured for use with EAS Update. null
otherwise.
Expo Go and development builds are not set to a specific channel and can run any updates compatible with their native runtime. Therefore, this value will always be null
when running an update on Expo Go or a development build.
Updates.checkAutomatically
Type: UpdatesCheckAutomaticallyValue | null
Determines if and when expo-updates checks for and downloads updates automatically on startup.
Updates.createdAt
Type: Date | null
If expo-updates
is enabled, this is a Date
object representing the creation time of the update that's currently running (whether it was embedded or downloaded at runtime).
In development mode, or any other environment in which expo-updates
is disabled, this value is
null.
Updates.isEmbeddedLaunch
Type: boolean
This will be true if the currently running update is the one embedded in the build, and not one downloaded from the updates server.
Updates.isEmergencyLaunch
Type: boolean
expo-updates
does its very best to always launch monotonically newer versions of your app so
you don't need to worry about backwards compatibility when you put out an update. In very rare
cases, it's possible that expo-updates
may need to fall back to the update that's embedded in
the app binary, even after newer updates have been downloaded and run (an "emergency launch").
This boolean will be true
if the app is launching under this fallback mechanism and false
otherwise. If you are concerned about backwards compatibility of future updates to your app, you
can use this constant to provide special behavior for this rare case.
Updates.isEnabled
Type: boolean
Whether expo-updates is enabled. This may be false in a variety of cases including:
When false, the embedded update is loaded.
Updates.manifest
If expo-updates
is enabled, this is the
manifest (or
classic manifest)
object for the update that's currently running.
In development mode, or any other environment in which expo-updates
is disabled, this object is
empty.
Updates.releaseChannel
Type: string
The name of the release channel currently configured in this standalone or bare app when using
classic updates. When using Expo Updates, the value of this field is always "default"
.
Updates.updateId
Type: string | null
The UUID that uniquely identifies the currently running update. The
UUID is represented in its canonical string form (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
) and
will always use lowercase letters. This value is null
when running in a local development environment or any other environment where expo-updates
is disabled.
Deprecated React hook to create an
UpdateEvent
listener subscription on mount, usingaddListener
. It callsremove()
on the subscription during unmount. This API is deprecated and will be removed in a future release corresponding with SDK 51. UseuseUpdates()
instead.
useUpdateEvents(listener)
Parameter | Type | Description |
---|---|---|
listener | (event: UpdateEvent) => void | A function that will be invoked with an |
void
Example
function App() {
const eventListener = (event) => {
if (event.type === Updates.UpdateEventType.ERROR) {
// Handle error
} else if (event.type === Updates.UpdateEventType.NO_UPDATE_AVAILABLE) {
// Handle no update available
} else if (event.type === Updates.UpdateEventType.UPDATE_AVAILABLE) {
// Handle update available
}
};
Updates.useUpdateEvents(eventListener);
// React Component...
}
useUpdates()
Hook that obtains information on available updates and on the currently running update.
the structures with information on currently running and available updates.
Example
import { StatusBar } from 'expo-status-bar';
import * as Updates from 'expo-updates';
import React from 'react';
import { Pressable, Text, View } from 'react-native';
export default function UpdatesDemo() {
const {
currentlyRunning,
availableUpdate,
isUpdateAvailable,
isUpdatePending
} = Updates.useUpdates();
React.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 pressHandler={() => Updates.checkForUpdateAsync()} text="Check manually for updates" />
{showDownloadButton ? (
<Button pressHandler={() => Updates.fetchUpdateAsync()} text="Download and run update" />
) : null}
<StatusBar style="auto" />
</View>
);
}
Updates.checkForUpdateAsync()
Checks the server to see if a newly deployed update to your project is available. Does not actually download the update. This method cannot be used in development mode, and the returned promise will be rejected if you try to do so.
Checking for an update uses a device's bandwidth and battery life like any network call. Additionally, updates served by Expo may be rate limited. A good rule of thumb to check for updates judiciously is to check when the user launches or foregrounds the app. Avoid polling for updates in a frequent loop.
A promise that fulfills with an UpdateCheckResult
object.
The promise rejects in Expo Go or if the app is in development mode, or if there is an unexpected error or timeout communicating with the server. It also rejects when expo-updates is not enabled.
Updates.clearLogEntriesAsync()
Clears existing expo-updates log entries.
For now, this operation does nothing on the client. Once log persistence has been implemented, this operation will actually remove existing logs.
Promise<void>
A promise that fulfills if the clear operation was successful.
The promise rejects if there is an unexpected error in clearing the logs.
Updates.fetchUpdateAsync()
Downloads the most recently deployed update to your project from server to the device's local storage. This method cannot be used in development mode, and the returned promise will be rejected if you try to do so.
Note:
reloadAsync()
can be called after promise resolution to reload the app using the most recently downloaded version. Otherwise, the update will be applied on the next app cold start.
A promise that fulfills with an UpdateFetchResult
object.
The promise rejects in Expo Go or if the app is in development mode, or if there is an unexpected error or timeout communicating with the server. It also rejects when expo-updates is not enabled.
Updates.getExtraParamsAsync()
Retrieves the current extra params.
This method cannot be used in Expo Go or development mode. It also rejects when expo-updates is not enabled.
Promise<undefined>
Updates.readLogEntriesAsync(maxAge)
Parameter | Type | Description |
---|---|---|
maxAge (optional) | number | Sets the max age of retrieved log entries in milliseconds. Default to 3600000 ms (1 hour). Default: 3600000 |
Retrieves the most recent expo-updates log entries.
A promise that fulfills with an array of UpdatesLogEntry
objects;
The promise rejects if there is an unexpected error in retrieving the logs.
Updates.reloadAsync()
Instructs the app to reload using the most recently downloaded version. This is useful for triggering a newly downloaded update to launch without the user needing to manually restart the app.
It is not recommended to place any meaningful logic after a call to await Updates.reloadAsync()
. This is because the promise is resolved after verifying that the app can
be reloaded, and immediately before posting an asynchronous task to the main thread to actually
reload the app. It is unsafe to make any assumptions about whether any more JS code will be
executed after the Updates.reloadAsync
method call resolves, since that depends on the OS and
the state of the native module and main threads.
This method cannot be used in Expo Go or development mode, and the returned promise will be rejected if you try to do so. It also rejects when expo-updates is not enabled.
Promise<void>
A promise that fulfills right before the reload instruction is sent to the JS runtime, or
rejects if it cannot find a reference to the JS runtime. If the promise is rejected in production
mode, it most likely means you have installed the module incorrectly. Double check you've
followed the installation instructions. In particular, on iOS ensure that you set the bridge
property on EXUpdatesAppController
with a pointer to the RCTBridge
you want to reload, and on
Android ensure you either call UpdatesController.initialize
with the instance of
ReactApplication
you want to reload, or call UpdatesController.setReactNativeHost
with the
proper instance of ReactNativeHost
.
Updates.setExtraParamAsync(key, value)
Parameter | Type |
---|---|
key | string |
value | undefined | null | string |
Sets an extra param if value is non-null, otherwise unsets the param.
Extra params are sent as an Expo Structured Field Value Dictionary
in the Expo-Extra-Params
header of update requests. A compliant update server may use these params when selecting an update to serve.
This method cannot be used in Expo Go or development mode. It also rejects when expo-updates is not enabled.
Promise<void>
Deprecated Adds a callback to be invoked when updates-related events occur (such as upon the initial app load) due to auto-update settings chosen at build-time. See also the
useUpdateEvents
React hook. This API is deprecated and will be removed in a future release corresponding with SDK 51. UseuseUpdates()
instead.
Updates.addListener(listener)
Parameter | Type | Description |
---|---|---|
listener | (event: UpdateEvent) => void | A function that will be invoked with an |
EventSubscription
An EventSubscription
object on which you can call remove()
to unsubscribe the
listener.
CurrentlyRunningInfo
Structure encapsulating information on the currently running app (either the embedded bundle or a downloaded update).
Name | Type | Description |
---|---|---|
channel (optional) | string | The channel name of the current build, if configured for use with EAS Update; undefined otherwise. |
createdAt (optional) | Date | If In development mode, or any other environment in which |
isEmbeddedLaunch | boolean | This will be true if the currently running update is the one embedded in the build, and not one downloaded from the updates server. |
isEmergencyLaunch | boolean |
|
manifest (optional) | Partial<Manifest> | If In development mode, or any other environment in which |
runtimeVersion (optional) | string | The runtime version of the current build. |
updateId (optional) | string | The UUID that uniquely identifies the currently running update if |
UpdateCheckResult
Literal Type: multiple types
The result of checking for a new update.
Acceptable values are: UpdateCheckResultRollBack
| UpdateCheckResultAvailable
| UpdateCheckResultNotAvailable
UpdateCheckResultAvailable
The update check result when a new update is found on the server.
Name | Type | Description |
---|---|---|
isAvailable | true | Whether an update is available. This property is false for a roll back update. |
isRollBackToEmbedded | false | Whether a roll back to embedded update is available. |
manifest | Manifest | The manifest of the update when available. |
reason | undefined | If no new update is found, this contains one of several enum values indicating the reason. |
UpdateCheckResultNotAvailable
The update check result if no new update was found.
Name | Type | Description |
---|---|---|
isAvailable | false | Whether an update is available. This property is false for a roll back update. |
isRollBackToEmbedded | false | Whether a roll back to embedded update is available. |
manifest | undefined | The manifest of the update when available. |
reason | UpdateCheckResultNotAvailableReason | If no new update is found, this contains one of several enum values indicating the reason. |
UpdateCheckResultRollBack
The update check result when a rollback directive is received.
Name | Type | Description |
---|---|---|
isAvailable | false | Whether an update is available. This property is false for a roll back update. |
isRollBackToEmbedded | true | Whether a roll back to embedded update is available. |
manifest | undefined | The manifest of the update when available. |
reason | undefined | If no new update is found, this contains one of several enum values indicating the reason. |
UpdateEvent
An object that is passed into each event listener when an auto-update check occurs.
Name | Type | Description |
---|---|---|
manifest (optional) | Manifest | If |
message (optional) | string | If |
type | UpdateEventType | Type of the event. |
UpdateFetchResult
Literal Type: multiple types
The result of fetching a new update.
Acceptable values are: UpdateFetchResultSuccess
| UpdateFetchResultFailure
| UpdateFetchResultRollBackToEmbedded
UpdateFetchResultFailure
The failed result of fetching a new update.
Name | Type | Description |
---|---|---|
isNew | false | Whether the fetched update is new (that is, a different version than what's currently running). False when roll back to embedded is true. |
isRollBackToEmbedded | false | Whether the fetched update is a roll back to the embedded update. |
manifest | undefined | The manifest of the fetched update. |
UpdateFetchResultSuccess
The successful result of fetching a new update.
Name | Type | Description |
---|---|---|
isNew | true | Whether the fetched update is new (that is, a different version than what's currently running). False when roll back to embedded is true. |
isRollBackToEmbedded | false | Whether the fetched update is a roll back to the embedded update. |
manifest | Manifest | The manifest of the fetched update. |
UpdateInfo
Literal Type: multiple types
Combined structure representing any type of update.
Acceptable values are: UpdateInfoNew
| UpdateInfoRollback
UpdatesLogEntry
An object representing a single log entry from expo-updates logging on the client.
Name | Type | Description |
---|---|---|
assetId (optional) | string | If present, the unique ID or hash of an asset associated with this log entry. |
code | UpdatesLogEntryCode | One of the defined code values for expo-updates log entries. |
level | UpdatesLogEntryLevel | One of the defined log level or severity values. |
message | string | The log entry message. |
stacktrace (optional) | string[] | If present, an iOS or Android native stack trace associated with this log entry. |
timestamp | number | The time the log was written, in milliseconds since Jan 1 1970 UTC. |
updateId (optional) | string | If present, the unique ID of an update associated with this log entry. |
UseUpdatesReturnType
The structures and methods returned by useUpdates()
.
Name | Type | Description |
---|---|---|
availableUpdate (optional) | UpdateInfo | If a new available update has been found, either by using checkForUpdate(),
or by the |
checkError (optional) | Error | If an error is returned from either the startup check for updates, or a call to |
currentlyRunning | CurrentlyRunningInfo | Information on the currently running app |
downloadError (optional) | Error | If an error is returned from either a startup update download, or a call to |
downloadedUpdate (optional) | UpdateInfo | If an available update has been downloaded, this will contain the information for that update. |
initializationError (optional) | Error | If an error occurs during initialization of |
isChecking | boolean | True if the app is currently checking for a new available update from the server. |
isDownloading | boolean | True if the app is currently downloading an update from the server. |
isUpdateAvailable | boolean | True if a new available update has been found, false otherwise. |
isUpdatePending | boolean | True if a new available update is available and has been downloaded. |
lastCheckForUpdateTimeSinceRestart (optional) | Date | A |
UpdateCheckResultNotAvailableReason
UpdateCheckResultNotAvailableReason Values
NO_UPDATE_AVAILABLE_ON_SERVER
UpdateCheckResultNotAvailableReason.NO_UPDATE_AVAILABLE_ON_SERVER = "noUpdateAvailableOnServer"
No update manifest or rollback directive received from the update server.
ROLLBACK_NO_EMBEDDED
UpdateCheckResultNotAvailableReason.ROLLBACK_NO_EMBEDDED = "rollbackNoEmbeddedConfiguration"
A rollback directive was received from the update server, but this app has no embedded update.
ROLLBACK_REJECTED_BY_SELECTION_POLICY
UpdateCheckResultNotAvailableReason.ROLLBACK_REJECTED_BY_SELECTION_POLICY = "rollbackRejectedBySelectionPolicy"
A rollback directive was received from the update server, but the directive does not pass the configured selection policy.
UPDATE_PREVIOUSLY_FAILED
UpdateCheckResultNotAvailableReason.UPDATE_PREVIOUSLY_FAILED = "updatePreviouslyFailed"
An update manifest was received from the update server, but the update has been previously launched on this device and never successfully launched.
UPDATE_REJECTED_BY_SELECTION_POLICY
UpdateCheckResultNotAvailableReason.UPDATE_REJECTED_BY_SELECTION_POLICY = "updateRejectedBySelectionPolicy"
An update manifest was received from the update server, but the update is not launchable, or does not pass the configured selection policy.
Deprecated The types of update-related events, used with
addListener()
anduseUpdateEvents()
. These APIs are deprecated and will be removed in a future release corresponding with SDK 51. UseuseUpdates()
instead.
UpdateEventType
UpdateEventType Values
NO_UPDATE_AVAILABLE
UpdateEventType.NO_UPDATE_AVAILABLE = "noUpdateAvailable"
No updates are available, and the most up-to-date update is already running.
UPDATE_AVAILABLE
UpdateEventType.UPDATE_AVAILABLE = "updateAvailable"
A new update has finished downloading to local storage. If you would like to start using this
update at any point before the user closes and restarts the app on their own, you can call
Updates.reloadAsync()
to launch this new update.
UpdateInfoType
The different possible types of updates.
Currently, the only supported type is UpdateInfoType.NEW
, indicating a new update that can be downloaded and launched
on the device.
In future, other types of updates may be added to this list.
UpdateInfoType Values
NEW
UpdateInfoType.NEW = "new"
This is the type for new updates found on or downloaded from the update server, that are launchable on the device.
ROLLBACK
UpdateInfoType.ROLLBACK = "rollback"
This type is used when an update is a directive to roll back to the embedded bundle.
UpdatesCheckAutomaticallyValue
The possible settings that determine if expo-updates will check for updates on app startup.
By default, Expo will check for updates every time the app is loaded. Set this to ON_ERROR_RECOVERY
to disable automatic checking unless recovering from an error. Set this to NEVER
to completely disable automatic checking. Must be one of ON_LOAD
(default value), ON_ERROR_RECOVERY
, WIFI_ONLY
, or NEVER
UpdatesCheckAutomaticallyValue Values
NEVER
UpdatesCheckAutomaticallyValue.NEVER = "NEVER"
Automatic update checks are off, and update checks must be done through the JS API.
ON_ERROR_RECOVERY
UpdatesCheckAutomaticallyValue.ON_ERROR_RECOVERY = "ON_ERROR_RECOVERY"
Only checks for updates when the app starts up after an error recovery.
ON_LOAD
UpdatesCheckAutomaticallyValue.ON_LOAD = "ON_LOAD"
Checks for updates whenever the app is loaded. This is the default setting.
WIFI_ONLY
UpdatesCheckAutomaticallyValue.WIFI_ONLY = "WIFI_ONLY"
Only checks for updates when the app starts and has a WiFi connection.
ASSETS_FAILED_TO_LOAD
UpdatesLogEntryCode.ASSETS_FAILED_TO_LOAD = "AssetsFailedToLoad"
INITIALIZATION_ERROR
UpdatesLogEntryCode.INITIALIZATION_ERROR = "InitializationError"
JS_RUNTIME_ERROR
UpdatesLogEntryCode.JS_RUNTIME_ERROR = "JSRuntimeError"
NONE
UpdatesLogEntryCode.NONE = "None"
NO_UPDATES_AVAILABLE
UpdatesLogEntryCode.NO_UPDATES_AVAILABLE = "NoUpdatesAvailable"
UNKNOWN
UpdatesLogEntryCode.UNKNOWN = "Unknown"
UPDATE_ASSETS_NOT_AVAILABLE
UpdatesLogEntryCode.UPDATE_ASSETS_NOT_AVAILABLE = "UpdateAssetsNotAvailable"
UPDATE_CODE_SIGNING_ERROR
UpdatesLogEntryCode.UPDATE_CODE_SIGNING_ERROR = "UpdateCodeSigningError"
UPDATE_FAILED_TO_LOAD
UpdatesLogEntryCode.UPDATE_FAILED_TO_LOAD = "UpdateFailedToLoad"
UPDATE_HAS_INVALID_SIGNATURE
UpdatesLogEntryCode.UPDATE_HAS_INVALID_SIGNATURE = "UpdateHasInvalidSignature"
UPDATE_SERVER_UNREACHABLE
UpdatesLogEntryCode.UPDATE_SERVER_UNREACHABLE = "UpdateServerUnreachable"
DEBUG
UpdatesLogEntryLevel.DEBUG = "debug"
ERROR
UpdatesLogEntryLevel.ERROR = "error"
FATAL
UpdatesLogEntryLevel.FATAL = "fatal"
INFO
UpdatesLogEntryLevel.INFO = "info"
TRACE
UpdatesLogEntryLevel.TRACE = "trace"
WARN
UpdatesLogEntryLevel.WARN = "warn"
Code | Description |
---|---|
ERR_UPDATES_DISABLED | A method call was attempted when the Updates module was disabled, or the application was running in development mode |
ERR_UPDATES_RELOAD | An error occurred when trying to reload the application and it could not be reloaded. For bare workflow apps, double check the setup steps for this module to ensure it has been installed correctly and the proper native initialization methods are called. |
ERR_UPDATES_CHECK | An unexpected error occurred when trying to check for new updates. Check the error message for more information. |
ERR_UPDATES_FETCH | An unexpected error occurred when trying to fetch a new update. Check the error message for more information. |
ERR_UPDATES_READ_LOGS | An unexpected error occurred when trying to read log entries. Check the error message for more information. |