Learn about different version types and how to manage them remotely or locally.
Android and iOS each expose two values that identify the version of an application; one that is visible in stores, and another that is visible only to developers.
In managed projects, we use fields version
/android.versionCode
/ios.buildNumber
in app.json to define versions, where android.versionCode
/ios.buildNumber
represents the developer-facing build version and version
is the user-facing value visible in stores. For bare projects, each of those values maps to specific parts of the native configuration:
version
field in app.json on iOS represents CFBundleShortVersionString
in Info.plist.version
field in app.json on Android represents versionName
in android/app/build.gradle.ios.buildNumber
field in app.json represents CFBundleVersion
in Info.plist.android.versionCode
field in app.json represents versionCode
in android/app/build.gradle.One of the most frequent causes of app store rejections is submitting a build with a duplicate version number. This happens when a developer forgets to increment the version number prior to running a build.
EAS Build can manage automatically incrementing these versions for you if you opt in to using the "remote" app version source. The default behavior is to use a "local" app version source, which means you control versions manually in their respective config files.
To simplify the descriptions, we will use app.json terminology (version
/versionCode
/buildNumber
) for the rest of this page, but unless stated otherwise, the same applies to bare projects.
With this eas.json, the version for all builds will be based on the value stored on EAS servers, and the version will be incremented remotely and only when building with production
profile.
{
"cli": {
"appVersionSource": "remote"
},
"build": {
"staging": {
"distribution": "internal",
"android": {
"buildType": "apk"
}
},
"production": {
"autoIncrement": true
}
}
}
With this eas.json, the version for all builds will be based on the value from app.json or native code. When you build using production
profile, the version will be incremented in the local code before the build.
{
"cli": {
"appVersionSource": "local"
},
"build": {
"staging": {
"distribution": "internal",
"android": {
"buildType": "apk"
}
},
"production": {
"autoIncrement": true
}
}
}
You can configure your project to rely on EAS servers to store and manage the version of your app. Add { "cli": { "appVersionSource": "remote" } }
in your eas.json. The remote version will be initialized with the value from the local project. If you would like to explicitly set the value directly, or EAS CLI is not able to detect what version the app is on, you can use the eas build:version:set
command. EAS stores version information scoped by account, slug, platform, and application ID/bundle identifier — so, for example, if you are building variants with different application IDs or bundle identifiers, versioning will be independent for each of them.
If you want to build your project locally in Android Studio or Xcode using the same version stored remotely on EAS, you can update your local project with the remote versions using eas build:version:sync
.
Enabling the autoIncrement
option in the remote app version source mode is currently only available for versionCode
/buildNumber
.
When using a remote app version source, the values in app.json will not be updated when the version is incremented remotely, and so the local and remote values will fall out of sync. The remote source values will be set on the native project when running a build, and they are the source of truth — however, the values specified in your app.json will be present in Constants.expoConfig
and Constants.manifest
exposed by expo-constants
. Use expo-application
to determine your application version at runtime instead, and remove versionCode
/buildNumber
from your app.json.
eas build:version:sync
command on Android does not support bare projects with multiple flavors, but the rest of the remote versioning functionality should work with all projects.autoIncrement
does not support the version
option."runtimeVersion": { "policy": "nativeVersion" }
. For similar behavior, use the "appVersion"
policy instead.The main goal of this feature is to avoid manual changes to the project every time you are uploading a new archive to run it on TestFlight/Play Store testing channels. When you are doing a production release, the user-facing version change should be explicit.
We recommend updating version
field after a new build goes live in the store, especially if you are using expo-updates
with an automatic runtime version policy. This marks the beginning of a new development cycle for a new version of your app. Learn more about deployment patterns.
By default, the source of truth for project versions is the local project source code itself. In this case, EAS does not write to the project, it reads the values and builds projects as they are.
You may opt in to auto incrementing versions locally with the autoIncrement
option on a build profile, but it comes with some limitations.
In the case of bare React Native projects, values in native code take precedence, and expo-constants
and expo-updates
read values from app.json. If you rely on version values from a manifest, you should keep them in sync with native code. Keeping these values in sync is especially important if you are using EAS Update with the runtime policy set to "runtimeVersion": { "policy": "nativeVersion" }
, because mismatched versions may result in the delivery of updates to the wrong version of an application. We recommend using expo-application
to read the version instead of depending on values from app.json.
autoIncrement
, you need to commit your changes on every build if you want the version change to persist. This can be difficult to coordinate when building on CI.autoIncrement
is not supported if you are using a dynamic config (app.config.js).autoIncrement
option is not supported and versions will not be listed in the build details page on expo.dev.