1--- 2title: Migrate from "expo build" 3description: A reference for migrating from "expo build" (classic builds) to EAS Build. 4--- 5 6import { Terminal } from '~/ui/components/Snippet'; 7 8This page covers practical differences you should know when migrating your Expo [managed app](/archive/managed-vs-bare/#managed-workflow) 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 [Creating your first build](/build/setup). 9 10One 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](/workflow/configuration) (**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. 11 12## SDK 41 and above projects are supported 13 14EAS 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](/workflow/upgrading-expo-sdk-walkthrough). 15 16## Understand the differences between classic and EAS builds 17 18Apps 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. 19 20With 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](https://expo.fyi/eas-build-archive). 21 22To learn more about how EAS Build creates a successful build of your project, see [Android](/build-reference/android-builds) and [iOS](/build-reference/ios-builds) build processes. 23 24### Files ignored in Git are not uploaded 25 26Any 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](https://expo.fyi/eas-build-archive#how-can-i-upload-files-to-eas-build-if-they-are-gitignored). 27 28### Libraries only in package.json are included in the app 29 30This 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`](https://blog.expo.dev/expo-managed-workflow-in-2021-5b887bbf7dbb). 31 32The 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](/eas-update/runtime-versions) that guarantees compatibility between a build's native code and an update to avoid this tradeoff. 33 34### Environment variables used by your app need to be defined for EAS Build 35 36If 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](/build-reference/variables). 37 38### Custom `"main"` entry point in package.json is not supported for SDK 48 and below 39 40If 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`](/versions/latest/sdk/register-root-component) to register your root component. 41 42For example, if your app's root component lives in **src/App.tsx**, the **index.js** should look like the following: 43 44```js index.js 45import { registerRootComponent } from 'expo'; 46import App from './src/App'; 47 48registerRootComponent(App); 49``` 50 51> **Note:** For SDK 49 and above, see [how to rename the main app file](/versions/latest/sdk/register-root-component/#what-if-i-want-to-name-my-main-app-file-something-other-than-appjs). 52 53### The `--config` flag is not supported 54 55If 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](https://expo.fyi/config-flag-migration). 56 57### Additional configuration is required to access private npm packages 58 59For more information on how to securely store `NPM_TOKEN` on EAS Build, see [Using private npm packages](/build-reference/private-npm-packages). 60 61### All assets referenced in source code are bundled 62 63With classic builds, `assetBundlePatterns` serves two purposes: 64 651. Assets that match the given patterns are bundled in the binary at build time. 662. Assets that match the given patterns determine the contents of an "atomic" update bundle. All files matching `assetBundlePatterns` need to be downloaded before an update is considered ready to launch. 67 68Only 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. 69 70### `Constants.manifest` is deprecated 71 72If you are using `Constants.manifest` to access fields, you should switch to `Constants.expoConfig` to access them from the [`expo-constants`](/versions/latest/sdk/constants) library. 73 74## App config (**app.json/app.config.js**) 75 76### `userInterfaceStyle` depends on `expo-system-ui` being installed 77 78On Android, selecting a native appearance mode with `userInterfaceStyle` (or `android.userInterfaceStyle`) in the **app.json** will only work if [`expo-system-ui`](/versions/latest/sdk/system-ui) is installed. This is because `expo-system-ui` enables locking the interface natively based on the **app.json**. 79 80Run the following command to install the `expo-system-ui` library: 81 82<Terminal cmd={['$ npx expo install expo-system-ui']} /> 83 84### `androidNavigationBar` depends on `expo-navigation-bar` being installed 85 86On 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. 87 88Also, consider migrating away from this property as the underlying Android APIs are deprecated. For more information, see the [migration guide](https://expo.fyi/android-navigation-bar-visible-deprecated). 89 90Run the following command to install the `expo-navigation-bar` library: 91 92<Terminal cmd={['$ npx expo install expo-navigation-bar']} /> 93 94### `splash` depends on `expo-splash-screen` being installed 95 96On 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`](/versions/latest/sdk/splash-screen) is installed in the project. 97 98Run the following command to install the `expo-splash-screen` library: 99 100<Terminal cmd={['$ npx expo install expo-splash-screen']} /> 101 102### `backgroundColor` depends on `expo-system-ui` being installed 103 104On 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`](/versions/latest/sdk/system-ui) is installed. This is because `expo-system-ui` includes code for setting the color natively based on the **app.json**. 105 106Run the following command to install the `expo-system-ui` library: 107 108<Terminal cmd={['$ npx expo install expo-system-ui']} /> 109 110## Updates 111 112If you are migrating from `expo build` and using `expo publish` to update your app, you are using [Classic Updates](/archive/classic-updates/introduction/). Once you migrate to EAS Build, you can also take advantage of our new-and-improved updates service, [EAS Update](/eas-update/introduction/). For in-depth information on how to migrate your project to EAS Update, see [Migrating from Classic updates to EAS Update](/eas-update/migrate-from-classic-updates). 113 114### No more automatic publishing before building 115 116With 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. 117 118With 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. 119 120Since 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](/guides/using-sentry/#configure-a--postpublish--hook). If you have other custom `postPublish` hooks, you can follow the same approach used in `sentry-expo` to support `postPublish` hook type of behavior. 121 122### `Constants.manifest` does not include update related fields 123 124Since 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. 125 126If 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`](/versions/latest/sdk/updates) library. 127 128### `Constants.appOwnership` will be `null` in the resulting standalone app 129 130The `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`](/versions/latest/sdk/constants/#executionenvironment). 131 132## Monorepos may require additional setup 133 134Classic builds had no knowledge of your repository setup. You could use a monorepo 135or birepo or trirepo, the service was entirely indifferent. As long as you could publish a 136bundle, that's all that was needed. 137 138EAS 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](/build-reference/build-with-monorepos/) and [Working with Monorepos](/guides/monorepos). 139 140## Miscellaneous 141 142### `expo-branch` is not supported on EAS Build 143 144Remove `expo-branch` from your app to build with EAS Build. You can 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). 145 146### `amazon-cognito-identity-js` is required if you use AWS Amplify 147 148In 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. 149 150### Animated WebP is not supported by default 151 152Most 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](/config-plugins/introduction/) to update **android/gradle.properties**. For more information on how to implement the config plugin, [see this example](https://forums.expo.dev/t/animated-webp-expected-to-work-with-eas-builds/58960/5?u=notbrent) from the community. 153 154### metro.config.js must export the entire default config from `expo/metro-config` 155 156> `expo/metro-config` is a versioned re-export of `@expo/metro-config`. 157 158Previously, with classic builds, your **metro.config.js** might have looked something like: 159 160```js metro.config.js 161const { getDefaultConfig } = require('expo/metro-config'); 162 163const defaultConfig = getDefaultConfig(__dirname); 164 165module.exports = { 166 resolver: { 167 assetExts: [...defaultConfig.resolver.assetExts, 'db'], 168 }, 169}; 170``` 171 172In 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: 173 174```js metro.config.js 175const { getDefaultConfig } = require('expo/metro-config'); 176 177const defaultConfig = getDefaultConfig(__dirname); 178 179defaultConfig.resolver.assetExts.push('db'); 180 181module.exports = defaultConfig; 182``` 183 184If 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](/guides/customizing-metro). 185 186## Troubleshooting build errors and crashes 187 188For more information, see [troubleshooting runtime and build errors, and crashes](/build-reference/troubleshooting). 189 190> **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. 191