1--- 2title: Migrating from "expo build" 3description: A reference for migrating from "expo build" to EAS Build. 4--- 5 6The 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 builds") 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"](/build/setup.mdx). 7 8One 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. 9 10### SDK 41+ apps are supported 11 12EAS Build only supports SDK 41+ managed projects. You must upgrade your project to migrate to EAS Build. 13 14### Expo config `userInterfaceStyle` depends on `expo-system-ui` being installed 15 16Selecting a native appearance mode with `userInterfaceStyle` (or `android.userInterfaceStyle`) in the project `app.json` will only work on Android if `expo-system-ui` is installed in the project. This is because `expo-system-ui` includes code for locking the interface natively based on the `app.json`. Run `npx expo install expo-system-ui` to add the library. This feature is only supported in **Expo SDK +43**. 17 18### Expo config `backgroundColor` depends on `expo-system-ui` being installed 19 20Selecting the root background color (for native modals and flipping orientations) with `ios.backgroundColor` in the project `app.json` will only work on iOS if `expo-system-ui` is installed in the project. This is because `expo-system-ui` includes code for setting the color natively based on the `app.json`. Run `npx expo install expo-system-ui` to add the library. This feature is only supported in **Expo SDK +43**. You can also remove references to `RCTRootViewBackgroundColor` in the `AppDelegate.m` file as this is now handled inside the `expo-system-ui` module. 21 22### Expo config `androidNavigationBar` depends on `expo-navigation-bar` being installed 23 24Selecting the navigation bar interaction behavior with `androidNavigationBar.visible` in the project `app.json` will only work on Android if `expo-navigation-bar` is installed in the project. Also consider migrating away from this property as the underlying Android APIs are deprecated: [Learn more](https://expo.fyi/android-navigation-bar-visible-deprecated). Run `npx expo install expo-navigation-bar` to install the library. This feature is only supported in **Expo SDK +43**. 25 26### Expo config `splash` depends on `expo-splash-screen` being installed 27 28Configuring the resizeMode or positioning of the splash screen with `splash` (or `android.splash`) in the project `app.json` will only work on Android if `expo-splash-screen` is installed in the project. Run `npx expo install expo-splash-screen` to install the library. This feature is only supported in **Expo SDK +43**. 29 30### Only libraries included in your package.json are included in the resulting standalone app 31 32This 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](https://blog.expo.dev/expo-managed-workflow-in-2021-5b887bbf7dbb)). The tradeoff here is that you need to be careful when publishing updates in order to avoid publishing an incompatible JavaScript bundle. Learn more in [updates](/build/updates.mdx). 33 34### Only files in your project folder that are not ignored in Git are uploaded to the build server 35 36EAS Build builds your app like other CI services — in short, the entire project is uploaded securely to the cloud, then it is downloaded by a build server, the dependencies are installed, and the build is run ([learn more](/build-reference/ios-builds)). Everything needed to build your app must be included in the project that is uploaded. The default mechanism for packaging your project is roughly equivalent to `git clone --depth 1`, and so anything that is in your `.gitignore` will not be uploaded (learn more in ["How projects are uploaded to EAS Build"](https://expo.fyi/eas-build-archive)). 37 38Developers often run into this with their "Google Services File", which they reference in their **app.json** / **app.config.js** but ignore in Git. If anything in your project is ignored in Git but necessary for a successful build, you can either remove it from `.gitignore` and commit it, or [encode with base64 and store in EAS Secrets, then decode at build time](https://github.com/expo/fyi/blob/main/eas-build-archive.mdx#how-can-i-upload-files-to-eas-build-if-they-are-gitignored). 39 40### The `--config` flag is not supported 41 42You 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"](https://expo.fyi/config-flag-migration). 43 44### No more automatic publishing before building 45 46With classic builds, the default behavior is to automatically publish your app with Classic Updates as an update 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 as a side effect. 47 48With 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. 49 50Because 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](https://github.com/expo/sentry-expo). If you have other custom `postPublish` hooks, you can follow the same approach used in `sentry-expo` to support `postPublish` hook type of behavior. 51 52### `Constants.manifest` does not include update related fields until updated 53 54Given that we no longer publish the app prior to builds, there is no update manifest available until the app has download an 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.channel`, you should switch to `Updates.channel` instead from the expo-updates library. 55 56### `Constants.appOwnership` will be `null` in the resulting standalone app 57 58The `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"`. 59 60### All assets referenced in source code are bundled 61 62With classic builds, `assetBundlePatterns` serves two purposes: 63 641. Assets that match the given patterns are bundled in the binary at build time. 652. Assets that match the given patterns determine the contents of an "atomic" update bundle. All of the files matching `assetBundlePatterns` need to be downloaded before an update is considered ready to launch. 66 67Only 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. 68 69### Custom `"main"` entry point in **package.json** is not yet supported 70 71If your app depends on a custom `"main"` entry point, you will need to remove that field from **package.json** and then create **index.js** in the root of your project and use [registerRootComponent](/versions/latest/sdk/register-root-component/) to register your root component. For example, if your app root component lives in **src/App.tsx**, your **index.js** should look like the following: 72 73```js index.js 74import { registerRootComponent } from 'expo'; 75import App from './src/App'; 76 77registerRootComponent(App); 78``` 79 80Support for custom entry points is in progress and is coming soon. 81 82### Monorepos may require additional setup 83 84Classic 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"](/build-reference/how-tos.mdx#how-to-set-up-eas-build-with). 85 86> Work is in progress to improve monorepo support for EAS Build managed projects. We recommend using [expo-yarn-workspaces](https://github.com/expo/expo/tree/main/packages/expo-yarn-workspaces/README.mdx). 87 88### Environment variables used by your app need to be defined for EAS Build 89 90If 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"](/build-reference/variables.mdx). 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. 91 92### Additional configuration is required to access private npm packages 93 94Learn more about how to securely store your `NPM_TOKEN` on EAS Build: ["Using private npm packages"](/build-reference/private-npm-packages). 95 96### `expo-branch` is not supported on EAS Build 97 98You will need to remove `expo-branch` from your app to build it with EAS Build. For **EAS Build**, you need to use the official [react-native-branch](https://github.com/BranchMetrics/react-native-branch-deep-linking-attribution) with [@config-plugins/react-native-branch](https://github.com/expo/config-plugins/tree/master/packages/react-native-branch) instead. 99 100### `amazon-cognito-identity-js` is required if you use AWS Amplify 101 102In 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 so you must install `amazon-cognito-identity-js` in order to link the native module depended on by AWS Amplify libraries. 103 104### Animated WebP is not supported by default 105 106Most apps do not use this format and support for it adds ~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` in `android/gradle.properties`. [This forums post](https://forums.expo.dev/t/animated-webp-expected-to-work-with-eas-builds/58960/5?u=notbrent) provides an example of a config plugin for making this change. 107 108### metro.config.js must export the entire default config from `expo/metro-config` 109 110> `expo/metro-config` is a versioned re-export of `@expo/metro-config`. 111 112Previously, with classic builds, your **metro.config.js** might have looked something like: 113 114```js metro.config.js 115const { getDefaultConfig } = require('expo/metro-config'); 116 117const defaultConfig = getDefaultConfig(__dirname); 118 119module.exports = { 120 resolver: { 121 assetExts: [...defaultConfig.resolver.assetExts, 'db'], 122 }, 123}; 124``` 125 126In 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: 127 128```js metro.config.js 129const { getDefaultConfig } = require('expo/metro-config'); 130 131const defaultConfig = getDefaultConfig(__dirname); 132 133defaultConfig.resolver.assetExts.push('db'); 134 135module.exports = defaultConfig; 136``` 137 138If you don't set up your **metro.config.js** file properly, your assets could fail to load in release builds. 139 140> **info** Having trouble migrating? [Join us in the #eas channel on the Expo Discord](https://discord.com/invite/4gtbPAdpaE) and let us know, we'll do our best to help. 141