Get Started
Feature Preview

Migrating from "expo build"

The purpose of this reference page is to call out some of the practical differences that you may need to account for when migrating your Expo managed app from expo build ("classic build") to EAS Build. If this is your first time using EAS Build, you can use this page as a companion to "Creating your first build".
One of the goals with EAS Build is to make it as easy as possible to migrate from expo build; for example, your app signing credentials will be automatically re-used, and the Expo SDK and your app.json configuration will all work the same as before. That said, there are some differences in the build process that may require additional configuration or small code changes.

SDK 41+ apps are supported

EAS Build only supports SDK 41+ managed projects. You must upgrade your project to migrate to EAS Build.

This often results in massive reductions in app size; managed apps built with EAS Build can be in the order of 10x smaller than the same app built with expo build (learn why). The tradeoff here is that you need to be careful when publishing over-the-air updates in order to avoid publishing an incompatible JavaScript bundle. Learn more in "Over-the-air updates".

You may be using expo build:[ios|android] --config app.production.json to switch app configuration files used by your project this is not supported in EAS Build, but it's easy to migrate to an alternative. Read more: "Migrating away from the --config flag in Expo CLI".

With classic builds, the default behavior is to automatically publish your app bundle prior to running a build. This had some unintended consequences; for example, sometimes developers would run a build and be surprised to learn that their existing app was updated over-the-air as a side effect.
With EAS Build, expo publish is not run as part of the build process. Instead, the JavaScript bundle is generated locally on EAS Build at build time and directly embedded in the app.
Because we no longer publish at build time, postPublish hooks in app.json will not be executed on build. If you use Sentry, be sure to update sentry-expo to the latest version and follow the updated instructions in the README. If you have other custom postPublish hooks, you can follow the same approach used in sentry-expo to support postPublish hook type of behavior.

Given that we no longer publish the app prior to builds, there is no update manifest available until the app has download an over-the-air update. Usually this means that at least for the first launch of the app you won't have some fields available. If you are using Constants.manifest to access update fields, in particular Constants.manifest.releaseChannel, you should switch to Updates.releaseChannel instead.

The Constants.appOwnership field no longer exists in standalone apps produced by EAS Build. If you were previously testing the environment with something like const isStandaloneApp = Constants.appOwnership === "standalone" then you can invert the logic: const isStandaloneApp = Constants.appOwnership !== "expo".

With classic builds, assetBundlePatterns serves two purposes:
  1. Assets that match the given patterns are bundled in the binary at build time.
  2. Assets that match the given patterns determine the contents of an "atomic" over-the-air update bundle. All of the files matching assetBundlePatterns need to be downloaded before an update is considered ready to launch.
Only the second purpose applies with the new build system. All assets referenced in your app source code are bundled into your app binary at build time, the same as in a default React Native app assetBundlePatterns is not used to determine what assets to bundle in the binary, it's only used for update bundles.

Classic builds had no knowledge of your repository set up, you could use a monorepo or birepo or trirepo, the service was entirely indifferent. As long as you were able to publish a bundle, that's all that was needed. EAS Build needs to be able to install all of your project dependencies and essentially set up your development environment inside of a worker, so in some cases that will require some additional configuration. Learn more: "How to set up EAS Build with a monorepo".
Work is in progress to improve monorepo support for EAS Build managed projects. We recommend using expo-yarn-workspaces.

If you use environment variables in your app.config.js or in your app source code (eg: with babel-plugin-inline-dotenv), you need to define these variables for your build profiles or in secrets, as described in "Environment variables and secrets". With classic builds this was not necessary because your app JavaScript was always built on your development machine (when you publish the app bundle prior to building), but now the app JavaScript is built in an EAS Build worker.

Learn more about how to securely store your NPM_TOKEN on EAS Build: "How to use private package repositories".

You will need to remove expo-branch from your app to build it with EAS Build. The plan is to add support to react-native-branch, the library maintained by engineers at Branch. If Branch support is a blocker for you, you can try to build your own config plugin to add react-native-branch to your app today.

Previously, with classic builds, your metro.config.js might have looked something like:
const { getDefaultConfig } = require('@expo/metro-config');

const defaultConfig = getDefaultConfig(__dirname);

module.exports = {
  resolver: {
    assetExts: [...defaultConfig.resolver.assetExts, 'db'],
In the example above, you're only exporting part of the default config, but EAS Build requires the full config. To do that, you should modify defaultConfig directly, and then return the resulting object, like this:
const { getDefaultConfig } = require('@expo/metro-config');

const defaultConfig = getDefaultConfig(__dirname);


module.exports = defaultConfig;
If you don't set up your metro.config.js file properly, your assets could fail to load in release builds.

Having trouble migrating? Join us in the #eas channel on the Expo Discord and let us know, we'll do our best to help.