Runtime versions and updates

Edit this page

Learn about different runtime version policies and how they may suit your project.


Runtime versions are a property that guarantees compatibility between a build's native code and an update. When a project is made into a build, the build will contain some native code that cannot be changed with an update. Therefore, an update must be compatible with a build's native code to run on the build.

To illustrate how builds and updates interact, take a look at the following diagram:

Builds can be thought of as two layers: a native layer that's built into the app's binary, and an update layer, that is swappable with other compatible updates. This separation allows us to ship bug fixes to builds as long as the update with the bug fix can run on the native layer inside the build. The "runtimeVersion" property allows us to guarantee that an update is compatible with a specific build's native code.

Since updates must be compatible with a build's native code, any time native code is updated, we're required to make a new build before publishing an update. Some developers only update native code when upgrading to a new Expo SDK, while others may upgrade native code between builds or at other intervals. Below is an explanation of different situations and configurations that may suite your project.

Setting "runtimeVersion"

To make managing the "runtimeVersion" property easier between builds and updates, we've created policies that derive the runtime version from another piece of information already present in your project. If these policies do not match the development flow of a project, there's also an option to set the "runtimeVersion" manually.

Runtime version policies

The available policies are documented in the expo-updates library documentation.

Custom runtime version

You can also set a custom runtime version that meets the runtime version formatting requirements:

{
  "expo": {
    "runtimeVersion": "1.0.0"
  }
}

This option is good for developers who want to manage the runtime version manually, separately from any other version numbers present in a project's app config. It gives the developer complete control over which updates are compatible with which builds.

Platform-specific runtime version

You can also set runtime version per-platform, for example

{
  "expo": {
    "android": {
      "runtimeVersion": "1.0.0"
    }
  }
}

Or:

{
  "expo": {
    "android": {
      "runtimeVersion": {
        "policy": "appVersion"
      }
    }
  }
}

When both a top level runtime and a platform specific runtime are set, the platform specific one takes precedence.

Avoiding incompatible updates

The main issue that can arise when publishing updates is that the update could rely on native code that the build it's running on does not support. For instance, imagine we made a build with a runtime version of "1.0.0". Then, we submitted that build to the app stores and released it to the public.

Later on, imagine that we developed an update that relied on a newly installed native library, like the expo-camera library, and we did not update the "runtimeVersion" property, so that it is still "1.0.0". If we published an update, the builds with the "runtimeVersion" of "1.0.0" would think the incoming update with the same runtime version was compatible and it would attempt to load the update. Since the update would make calls to code that does not exist inside the build, expo-updates may detect an error and attempt to roll back to the previously working update (learn more about error recovery behavior).

The following are some strategies to avoid deploying updates that are incompatible with a build's native code.

Use a runtime version policy that automatically updates the runtime version when native code is updated

The "appVersion" policy will increment the runtime version whenever the app version is incremented, but if you forget to bump the app version when changing the native runtime, then you'll have a runtime version mismatch. If you want to make incompatible updates extremely unlikely, at the cost of making it necessary to create builds more often, then you can use the "fingerprint" policy. This will increment the runtime version whenever anything that may impact the native runtime changes (learn more about fingerprinting).

Manually increment the runtime version

Whenever installing or updating native code, manually increment the "runtimeVersion" property in the project's app config.

Roll out the update gradually

If you're not sure about the impact of a new update, you can roll it out to a small group of users first. Use rollouts to publish the update to a small percentage of users and monitor the error rate for the update on the EAS dashboard. If you are noticing high error rates, then cancel the rollout. If you already rolled it out fully, then roll it back.

Manually verify updates with a smaller group of users

When you deploy to production, create a preview build that uses the same runtime but points to a different channel. Test your updates on those builds before promoting them to production (learn more about this in the deployment guide). Alternatively, you can opt-in certain users of your app to receive the update by overriding update parameters at runtime (learn more).