A reference for migrating from "expo build" (classic builds) to EAS Build.
This page covers practical differences you should know when migrating your Expo managed app from expo build
(also known as classic builds) to EAS Build. If this is your first time using EAS Build, you can use this page as a companion to Create your first build.
One of the goals of 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 config (app.json) configuration will all work the same as before. However, some differences between the two build processes require additional configuration or small code changes.
EAS Build only supports SDK 41 and above projects. You must upgrade your project to migrate to EAS Build. For more information, see upgrading Expo SDK.
Apps built with EAS Build are like other CI services — the entire project is uploaded securely to the cloud, then downloaded by a build server, the dependencies are installed, and the build is run.
With classic builds, your app's JavaScript is built on your development machine (when you publish the app bundle before building), but now the app's JavaScript is built on an EAS Build builder. Everything required to build your app must be included in the project to be uploaded.
To learn more about how EAS Build creates a successful build of your project, see Android and iOS build processes.
Any file or directory that is ignored in the .gitignore file will not be uploaded. For example, when Google Services (google-services.json or GoogleService-Info.plist) files are added in .gitignore, they are ignored. For a file like this or any other in your project that is necessary for a successful build, you can either remove it from .gitignore and commit it or encode with base64 and store it in EAS Secrets, then decode at build time.
This often results in massive reductions in app size. Managed apps built with EAS Build can be 10x smaller than the same app built with expo build
.
The tradeoff when migrating from expo build
is that you need to be careful when publishing updates to avoid publishing an incompatible JavaScript bundle because the build contains some native code that cannot be changed with an update. However, you can set up and use runtime version property that guarantees compatibility between a build's native code and an update to avoid this tradeoff.
If you use environment variables in your app.config.js or in your app source code (for example, 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.
"main"
entry point in package.json is not supported for SDK 48 and belowIf your app uses SDK 48 or below and depends on a custom "main"
entry point, remove it from package.json. Then, create index.js at the root of your project and use registerRootComponent
to register your root component.
For example, if your app's root component lives in src/App.tsx, the index.js should look like the following:
import { registerRootComponent } from 'expo';
import App from './src/App';
registerRootComponent(App);
Note: For SDK 49 and above, see how to rename the main app file.
--config
flag is not supportedIf you are using expo build:[ios|android] --config app.production.json
to switch app configuration files used by your project, you'll have to migrate to an alternative since this is not supported in EAS Build. For more information, see Migrating away from the --config
flag in Expo CLI.
For more information on how to securely store NPM_TOKEN
on EAS Build, see Using private npm packages.
With classic builds, assetBundlePatterns
serves two purposes:
assetBundlePatterns
need to be downloaded before an update is considered ready to launch.Only the second purpose applies to the EAS 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.
Constants.manifest
is deprecatedIf you are using Constants.manifest
to access fields, you should switch to Constants.expoConfig
to access them from the expo-constants
library.
userInterfaceStyle
depends on expo-system-ui
being installedOn Android, selecting a native appearance mode with userInterfaceStyle
(or android.userInterfaceStyle
) in the app.json will only work if expo-system-ui
is installed. This is because expo-system-ui
enables locking the interface natively based on the app.json.
Run the following command to install the expo-system-ui
library:
-
npx expo install expo-system-ui
androidNavigationBar
depends on expo-navigation-bar
being installedOn Android, selecting the navigation bar interaction behavior with androidNavigationBar.visible
in the app.json will only work if expo-navigation-bar
is installed in the project.
Also, consider migrating away from this property as the underlying Android APIs are deprecated. For more information, see the migration guide.
Run the following command to install the expo-navigation-bar
library:
-
npx expo install expo-navigation-bar
splash
depends on expo-splash-screen
being installedOn Android, configuring the resizeMode
or positioning of the splash screen with splash
(or android.splash
) in the app.json will only work if expo-splash-screen
is installed in the project.
Run the following command to install the expo-splash-screen
library:
-
npx expo install expo-splash-screen
backgroundColor
depends on expo-system-ui
being installedOn iOS, selecting the root background color (for native modals and flipping orientations) with ios.backgroundColor
in the app.json will only work if expo-system-ui
is installed. This is because expo-system-ui
includes code for setting the color natively based on the app.json.
Run the following command to install the expo-system-ui
library:
-
npx expo install expo-system-ui
If you are migrating from expo build
and using expo publish
to update your app, you are using Classic Updates. Once you migrate to EAS Build, you can also take advantage of our new-and-improved updates service, EAS Update. For in-depth information on how to migrate your project to EAS Update, see Migrating from Classic updates to EAS Update.
With classic builds, the default behavior was to automatically publish your app with Classic Updates as an update before 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 as a side effect.
With EAS Build, the Classic Update's expo publish
command 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.
Since we no longer publish at build time, postPublish
hooks in app.json will not be executed on the build. If you use Sentry, update the sentry-expo
library to the latest version and follow the updated instructions in Using Sentry. If you have other custom postPublish
hooks, you can follow the same approach used in sentry-expo
to support postPublish
hook type of behavior.
Constants.manifest
does not include update related fieldsSince we no longer publish the app before builds, no update manifest is available until the app downloads an update. Usually, this means that for the first launch of the app, you won't have some fields available.
If you are using Constants.manifest.channel
, you should switch to Updates.releaseChannel
(for Classic Updates) or Updates.channel
(for EAS Update) from the expo-updates
library.
Constants.appOwnership
will be null
in the resulting standalone appThe Constants.appOwnership
field no longer exists in apps produced by EAS Build. If you were previously testing the environment with something similar to const isStandaloneApp = Constants.appOwnership === "standalone"
, switch to use Constants.executionEnvironment
.
Classic builds had no knowledge of your repository setup. You could use a monorepo or birepo or trirepo, the service was entirely indifferent. As long as you could publish a bundle, that's all that was needed.
EAS Build needs to be able to install all of your project dependencies to set up the development environment inside of a builder. In some cases, that will require some additional configuration. For more information, see How to set up EAS Build with a monorepo and Working with Monorepos.
expo-branch
is not supported on EAS BuildRemove expo-branch
from your app to build with EAS Build. You can use the official react-native-branch
with @config-plugins/react-native-branch
.
amazon-cognito-identity-js
is required if you use AWS AmplifyIn projects built with expo build
the native primitives required by AWS Amplify are included in every app. This is not the case in EAS Build, and you must install amazon-cognito-identity-js
to link the native module depended on by AWS Amplify libraries.
Most apps do not use this format and support for it adds around 3.4 MB to the final app size, so it is omitted by default. You can enable it by switching expo.webp.animated=false
to expo.webp.animated=true
using a custom Config plugin to update android/gradle.properties. For more information on how to implement the config plugin, see this example from the community.
expo/metro-config
expo/metro-config
is a versioned re-export of@expo/metro-config
.
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. However, EAS Build requires the full config. To do that, you have to modify defaultConfig
directly, and then return the resulting object as shown below:
const { getDefaultConfig } = require('expo/metro-config');
const defaultConfig = getDefaultConfig(__dirname);
defaultConfig.resolver.assetExts.push('db');
module.exports = defaultConfig;
If you don't set up your metro.config.js file properly, your assets could fail to load in release builds. For more information, see Customizing Metro.
For more information, see troubleshooting runtime and build errors, and crashes.
Having trouble migrating? Join us in the #eas channel on the Discord and Forums and let us know.