Guides
Plan-enterprise-icon
Expo Application Services
API Reference

App version management

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.

Examples

Triangle-down-icon
Remote version source
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
    }
  }
}
Triangle-down-icon
Local version source
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.
  • It's not supported if you are using EAS Update and runtime policy set to "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.

  • With 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).
  • For bare React Native projects with Gradle configuration that supports multiple flavors, EAS CLI is not able to read or modify the version, so autoIncrement option is not supported and versions will not be listed in the build details page on expo.dev.