Native project upgrade helper

Edit this page

View file-by-file diffs of all the changes you need to make to your native projects to upgrade them to the next Expo SDK version.


If you manage your native projects (previously known as bare workflow), to upgrade to the latest Expo SDK, you have to make changes to your native projects. It can be a complex process to find which native file changes and what to update in which file.

The following guide provides diffs to compare native project files between your project's current SDK version and the target SDK version you want to upgrade. You can use them to make changes to your project depending on the expo package version your project uses. The tools on this page are similar to React Native Upgrade Helper. However, they are oriented around projects that use Expo modules and related tooling.

Interested in avoiding upgrading native code altogether? See Continuous Native Generation (CNG) to learn how Expo Prebuild can generate your native projects before a build.

Upgrade native project files

Once you have upgraded your Expo SDK version and related dependencies, use the diff tool below to learn about changes you need to make to your native project and bring them up to date with the current Expo SDK version.

Choose your from SDK version and to SDK version to see the generated diff. Then, apply those changes to your native projects by copying and pasting or manually making changes to the project files.

From SDK version:

To SDK version:

Native code changes from SDK 53 to 54

android/app/build.gradle
MODIFIED
6464}
6565
6666/**
67 * Set this to true to Run Proguard on Release builds to minify the Java bytecode.
67 * Set this to true in release builds to optimize the app using [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization).
6868 */
69def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()
69def enableMinifyInReleaseBuilds = (findProperty('android.enableMinifyInReleaseBuilds') ?: false).toBoolean()
7070
7171/**
7272 * The preferred build flavor of JavaScriptCore (JSC)
9494 targetSdkVersion rootProject.ext.targetSdkVersion
9595 versionCode 1
9696 versionName "1.0"
97
98 buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
9799 }
98100 signingConfigs {
99101 debug {
112114 // see https://reactnative.dev/docs/signed-apk-android.
113115 signingConfig signingConfigs.debug
114116 shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
115 minifyEnabled enableProguardInReleaseBuilds
117 minifyEnabled enableMinifyInReleaseBuilds
116118 proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
117119 crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
118120 }
android/app/src/main/java/com/helloworld/MainApplication.kt
MODIFIED
55
66import com.facebook.react.PackageList
77import com.facebook.react.ReactApplication
8import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
89import com.facebook.react.ReactNativeHost
910import com.facebook.react.ReactPackage
1011import com.facebook.react.ReactHost
11import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
12import com.facebook.react.common.ReleaseLevel
13import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint
1214import com.facebook.react.defaults.DefaultReactNativeHost
13import com.facebook.react.soloader.OpenSourceMergedSoMapping
14import com.facebook.soloader.SoLoader
1515
1616import expo.modules.ApplicationLifecycleDispatcher
1717import expo.modules.ReactNativeHostWrapper
1919class MainApplication : Application(), ReactApplication {
2020
2121 override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(
22 this,
23 object : DefaultReactNativeHost(this) {
24 override fun getPackages(): List<ReactPackage> {
25 val packages = PackageList(this).packages
26 // Packages that cannot be autolinked yet can be added manually here, for example:
27 // packages.add(MyReactNativePackage())
28 return packages
29 }
22 this,
23 object : DefaultReactNativeHost(this) {
24 override fun getPackages(): List<ReactPackage> =
25 PackageList(this).packages.apply {
26 // Packages that cannot be autolinked yet can be added manually here, for example:
27 // add(MyReactNativePackage())
28 }
3029
3130 override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"
3231
3332 override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
3433
3534 override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
36 override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
3735 }
3836 )
3937
4240
4341 override fun onCreate() {
4442 super.onCreate()
45 SoLoader.init(this, OpenSourceMergedSoMapping)
46 if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
47 // If you opted-in for the New Architecture, we load the native entry point for this app.
48 load()
43 try {
44 DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase())
45 } catch (e: IllegalArgumentException) {
46 DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.STABLE
4947 }
48 loadReactNative(this)
5049 ApplicationLifecycleDispatcher.onApplicationCreate(this)
5150 }
5251
android/gradle.properties
MODIFIED
1515# When configured, Gradle will run in incubating parallel mode.
1616# This option should only be used with decoupled projects. More details, visit
1717# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18# org.gradle.parallel=true
18org.gradle.parallel=true
1919
2020# AndroidX package structure to make it clearer which packages are bundled with the
2121# Android operating system, and which are packaged with your app's APK
4141# If set to false, you will be using JSC instead.
4242hermesEnabled=true
4343
44# Use this property to enable edge-to-edge display support.
45# This allows your app to draw behind system bars for an immersive UI.
46# Note: Only works with ReactActivity and should not be used with custom Activity.
47edgeToEdgeEnabled=true
48
4449# Enable GIF support in React Native images (~200 B increase)
4550expo.gif.enabled=true
4651# Enable webp support in React Native images (~85 KB increase)
android/gradle/wrapper/gradle-wrapper.properties
MODIFIED
11distributionBase=GRADLE_USER_HOME
22distributionPath=wrapper/dists
3distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
3distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
44networkTimeout=10000
55validateDistributionUrl=true
66zipStoreBase=GRADLE_USER_HOME
android/gradlew
MODIFIED
114114 NONSTOP* ) nonstop=true ;;
115115esac
116116
117CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
117CLASSPATH="\\\"\\\""
118118
119119
120120# Determine the Java command to use to start the JVM.
213213set -- \
214214 "-Dorg.gradle.appname=$APP_BASE_NAME" \
215215 -classpath "$CLASSPATH" \
216 org.gradle.wrapper.GradleWrapperMain \
216 -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
217217 "$@"
218218
219219# Stop when "xargs" is not available.
android/gradlew.bat
MODIFIED
7070:execute
7171@rem Setup the command line
7272
73set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73set CLASSPATH=
7474
7575
7676@rem Execute Gradle
77"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
77"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
7878
7979:end
8080@rem End local scope for the variables with windows NT shell
ios/HelloWorld.xcodeproj/project.pbxproj
MODIFIED
168168 files = (
169169 );
170170 inputPaths = (
171 "$(SRCROOT)/.xcode.env",
172 "$(SRCROOT)/.xcode.env.local",
171173 );
172174 name = "Bundle React Native code and images";
173175 outputPaths = (
ios/HelloWorld/Images.xcassets/SplashScreenLegacy.imageset/Contents.json
ADDED
1{
2 "images" : [
3 {
4 "filename" : "SplashScreenLegacy.png",
5 "idiom" : "universal",
6 "scale" : "1x"
7 },
8 {
9 "idiom" : "universal",
10 "scale" : "2x"
11 },
12 {
13 "idiom" : "universal",
14 "scale" : "3x"
15 }
16 ],
17 "info" : {
18 "author" : "xcode",
19 "version" : 1
20 }
21}
ios/Podfile
MODIFIED
66
77ENV['RCT_NEW_ARCH_ENABLED'] = '0' if podfile_properties['newArchEnabled'] == 'false'
88ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] = podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
9
9ENV['RCT_USE_RN_DEP'] = '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false'
10ENV['RCT_USE_PREBUILT_RNCORE'] = '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false'
1011platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1'
11install! 'cocoapods',
12 :deterministic_uuids => false
1312
1413prepare_react_native_project!
1514
4948 :mac_catalyst_enabled => false,
5049 :ccache_enabled => podfile_properties['apple.ccacheEnabled'] == 'true',
5150 )
52
53 # This is necessary for Xcode 14, because it signs resource bundles by default
54 # when building for devices.
55 installer.target_installation_results.pod_target_installation_results
56 .each do |pod_name, target_installation_result|
57 target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
58 resource_bundle_target.build_configurations.each do |config|
59 config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
60 end
61 end
62 end
6351 end
6452end
package.json
MODIFIED
22 "name": "expo-template-bare-minimum",
33 "description": "This bare project template includes a minimal setup for using unimodules with React Native.",
44 "license": "0BSD",
5 "version": "53.0.38",
5 "version": "54.0.1",
66 "main": "index.js",
77 "scripts": {
88 "start": "expo start --dev-client",
1111 "web": "expo start --web"
1212 },
1313 "dependencies": {
14 "expo": "~53.0.20",
15 "expo-status-bar": "~2.2.3",
16 "react": "19.0.0",
17 "react-native": "0.79.6"
18 },
19 "devDependencies": {
20 "@babel/core": "^7.20.0"
14 "expo": "~54.0.0-preview.1",
15 "expo-status-bar": "~3.0.1",
16 "react": "19.1.0",
17 "react-native": "0.81.0"
2118 }
2219}