- read

Expo SDK 49

Brent Vatne 10

Today we’re announcing the release of Expo SDK 49. SDK 49 includes React Native 0.72.4. Thank you to everyone who helped with beta testing.

Integrated network debugging and React devtools

Network debugging is now available in the JS debugger. For several SDK releases, it has been possible to launch the JS (Hermes) debugger directly from Expo CLI with the j shortcut. This debugger now also includes support for Network requests when your app runs in expo-dev-client or Expo Go.

Open up the network inspector with “Open JS debugger” from Expo Go or a development build with expo-dev-client, and then clicking on the “Network” tab in the DevTools window that opens.

You can also see images loaded over the network in the network inspector.

Additionally, React devtools is now built-in to Expo CLI: you can launch it by pressing shift+m and then selecting “Start React devtools”

Launch directly into React devtools from the CLI. Toggle the element inspector in your app to select elements and see them highlighted in React devtools.

Debug in VS Code with the Expo Tools Extension

We’ve added experimental support for debugging your app JavaScript code directly from VS Code with the Expo Tools Extension (GitHub)! With the extension installed and your app running, launch the command palette (shift+⌘+P on macOS) and select “Expo: Debug Expo app on a device or simulator, using Hermes”.

Expo Router v2.0

The next major release for universal file-based routing. Expo Router v2 now has opt-in support for build-time static rendering on web, automatically statically typed-routes, and async route loading. Also note when upgrading that you will want to change useSearchParams to either useLocalSearchParams or useGlobalSearchParams. Learn more in the “Announcing Expo Router v2” blog post.

Other Highlights

  • An assortment of improvements to Expo SDK modules: for example, expo-screen-orientation was largely rebuilt to address a number of long-standing issues, expo-blur now supports Android (caveat: this may have a meaningful performance impact, especially on low-end devices), and expo-clipboard now exports a UIPasteControl button. For a full list of other improvements contributed by the community and Expo engineers, refer to the CHANGELOG.
  • Expo Modules API improvements. We recently introduced local modules, which allow you to write native code in your app without needing to create a library or manage your app’s native project — try it out in an SDK 49 project: npx create-expo-module --local. Additionally, you can now add native async functions on component refs, and synchronous functions can now take arguments of raw JS types such as JavaScriptValue, JavaScriptObject and JavaScriptFunction.
  • Expo Go for the iOS simulator now runs natively on Apple silicon. Additionally, you can experiment with running Expo Go directly on Apple silicon Macs, without the simulator, through the TestFlight build — however, there are some UI issues that we’re still working on fixing. Learn more about how this works.
  • Metro is now recommended for web. The @expo/webpack-config package is currently in maintenance mode, and our efforts on web support are focused on Metro. We strongly recommend all new projects use Metro for web. Many existing projects should work well with Metro as long as they don’t require any of the few remaining features only supported by Webpack. Refer to the “Known Regressions” section below for more information on issues you may encounter using Webpack with SDK 49.
  • npx expo start no longer requires the --dev-client flag for development builds. It will default to targeting development builds if you have expo-dev-client installed in your project. You can use s to toggle between development build and Expo Go targets, this will change the URL that the QR code points to and that the a/ikeyboard shortcuts launch into.
Press `s` to toggle between Expo Go and development build targets in the Expo CLI interactive prompt.
  • expo export:embed has replaced the@react-native-community/cli bundle command in the “Bundle React Native code and images” build phase. This has allowed us to add support for custom entry points — you can change "main" in package.json to point to any source file (be sure to use registerRootComponent in the new entry file, if you aren’t using Expo Router).
  • Expo CLI now has built-in support for environment variables in Metro. Existing approaches in the React Native ecosystem have issues such as the need for clearing Babel caches to update variables, and they depend on developers to opt-in to security options like exclude and include lists. Our approach overcomes these problem by integrating the process into the Expo Metro config and following the popular convention in the JavaScript ecosystem to include “PUBLIC” in the prefix of environment variable names. In SDK 49, you can define your variables in .env (and similar files such as .env.local, see the full list) with the EXPO_PUBLIC_ prefix and they’ll be included in your app JavaScript if they are used. Learn more.
Environment variables and the files that they are loaded from (.env, .env.local, etc.) will be printed when you run commands with Expo CLI.
  • Selectively opt out of package version validations. There may be circumstances where you want to use a version of a package is different from the version recommended by npx expo install. For example, you are testing a new version of react-native-reanimated to verify that it works well in your app and fixes a bug that you encountered. Now you want to 1) not be warned by npx expo start or npx expo-doctor and 2) not have that package version changed when you run npx expo install --fix. We now support the expo.install.exclude key in package.json, which allows you to specify which packages you’d like to exclude from validations. Learn more.
Here’s how you would configure your package.json to skip Expo CLI / Doctor warnings about using a react-native-reanimated version that differs from the recommended version for the SDK.
  • scheme in app config can now be an array. Previously, it was necessary to use a config plugin to add additional schemes. You can now use either an array of strings or a string: scheme: ['myapp', 'fb1234'] or scheme: 'myapp'.
  • Experimental support for Fabric in expo-dev-client. Try it: npx create-expo-app@latest -e with-new-arch. The only module that does not yet support the New Architecture is expo-updates.
  • Updated recommended TypeScript version to ^5.1.3. SDK 48 used ^4.9.4. Learn about the changes in the TypeScript 5.0 and 5.1 release notes, and learn how to use TypeScript in your project if you’re not already.
  • React Native 0.72.4, React Native Web 0.19.6. As usual, there were many improvements in this release, refer to the React Native CHANGELOG, Release Notes, and the React Native Web Release Notes. The React version is unchanged from 0.71 — it is still 18.2.0. Note that theProgressBarAndroid and ProgressViewIOS components have been removed in React Native 0.72.0, after being deprecated for a long time. Additionally, be sure to check the React Native Web breaking changes if you use that platform.

Introducing EAS Insights

A preview of EAS Insights is now available to all developers. The goal of this service is to give you the data you need to make good decisions, and, as always, help you iterate faster and with confidence. It will also be deeply integrated into other services like Build, Submit and Update (we’ll share more about this in the near future). While in preview, Insights is free to use.

An example of the type of data accessible through the EAS Insights feature preview (data in this screenshot is simulated).

Included in this preview release is an “Insights” tab on your project sidebar. Current users of EAS Update will see a limited set of insights without making any changes to their project, but we encourage any developers interested in EAS Insights to install the expo-insights module. Learn more.

The future of EAS Insights depends on your feedback: let us know what insights you need, and which you think you would benefit most from being built directly into EAS. Reach out to us with comments or suggestions on Discord, Twitter, or expo.dev/contact.

EAS Build

  • Added Xcode 14.3.1 image, the default for SDK 49 / React Native 0.72. Learn more.
  • Large workers are now available for both Android and iOS builds. Large iOS builds currently run on M2 Pro or M2 hosts, and tend to run about 40–50% faster than medium workers. Large Android builds have double the memory and number of CPUs compared to medium — they run on n2-standard-8, while medium run on n2-standard-4. Learn more.
  • Rename devices registered for iOS internal distribution with eas device:rename. UDIDs are perfectly good identifiers for machines, but for humans, we tend to prefer names like “Bob’s blue iPhone 14”. Learn more.

EAS Update

  • Expo Go is now more flexible and will open your project as long as the version of its expo dependency matches a supported SDK version. Previously, when you set the runtimeVersion to anything except for the sdkVersion policy, Expo Go would consider it incompatible and refuse to launch it. It’s important to note that if your project depends on native APIs that are not in the Expo Go runtime for the given SDK version, your project will likely still not run. In these cases, we recommend you use development builds or provide fallbacks in your application code if certain native APIs aren’t available.
  • Updates.checkForUpdateAsync (🔗) and Updates.fetchUpdateAsync (🔗) will no longer throw an error when the client successfully contacts the update server but there isn’t an update available. Clients on all platforms using the latest version of the expo-updates module will receive lightweight HTTP 204 No Content responses from EAS Update when there isn’t a new update available for the client (related specification). We still recommend catching errors to handle when clients can’t connect to the internet and potential server outages, but we expect this change to make it much easier to detect when there’s actually a problem fetching updates.
  • expo-updates on Android app now uses Brotli compression, which compresses JavaScript about 15% more than gzip.
  • With the release of EAS Update, we are sunsetting “expo publish” and Classic Updates next year. Publishing Classic Updates will be supported until 2024. Existing apps will keep working and receive updates published before the cutoff. SDK 49 will be the last version to support Classic Updates. To continue using the deprecated expo publish command, set updates.useClassicUpdates to true in your app config.

🏗 Deprecations, renamings, and removals

  • Updating your Android Expo Modules for Gradle 8: if you’ve had the joy of working with the Expo Modules API to build a native module in Kotlin, you will want to refer to expo.fyi/expo-modules-gradle8-migration for instructions on how to ensure your module is compatible with Gradle 8.
  • sentry-expo major version bump: the new major release of [email protected] now uses Sentry React Native SDK version 5, which supports New Architecture. Refer to the migration guide for more details on changes that might affect your project.
  • Expo CLI now defaults to port 8081 for all projects, rather than 19000. The port 19000 was used only for historical reasons, and it’s no longer needed, so we converged on 8081.
  • Remote debugging for JSC is disabled in Expo Go and expo-dev-client. JSC remote debugging never worked particularly well compared to debugging with Hermes, and it has become unreliable over time. For more context, refer to this pull request to React Native, which will be included in their next release.
  • Constants.manifest is deprecated; use Constants.expoConfig instead. The manifest in an Expo app specifies the app’s assets (like its JavaScript) and configuration data (often fields from app.json). Previously, Constants.manifest was the way to access an app’s configuration data. With SDK 49, Constants.expoConfig replaces Constants.manifest for this purpose. Refer to expo.fyi/why-constants-expoconfig to learn more about this change.
  • AuthSession proxy has been removed: the useProxy option and AuthSession.startAsync method have been removed from expo-auth-session@5, following this recommendation. You can continue to use expo-auth-session@4 if you need a bit more time to migrate off of the auth proxy. If you currently use the auth proxy to work around an authentication provider not redirecting to custom schemes, we recommend switching from Expo Go to development builds and using the native SDK from that provider. For example: Facebook, Google.
  • android:usesCleartextTraffic is now based on system defaults. It’s explicitly set to enabled in debug builds, and in other variants it is unspecified, which means that on API 27 and below it will default to true, and on API 28 and above it will default to false. If you depend on network requests to unsecured endpoints in production on Android, you will need to enable this manually through expo-build-properties.
  • Reanimated 3 drops support for the legacy Reanimated API. If you depend on libraries that have not yet updated to the faster and more ergonomic new API, you may see errors related to this when you upgrade. Learn more.
  • Support for expo-face-detector has been removed from Expo Go. This change was necessary in order to support Apple Silicon natively in Expo Go iOS simulator builds. You can continue using the library outside of Expo Go as you have previously.

⏪ Known Regressions

  • H̶e̶r̶m̶e̶s̶ ̶d̶e̶b̶u̶g̶g̶e̶r̶ ̶f̶o̶r̶ ̶A̶n̶d̶r̶o̶i̶d̶ ̶i̶s̶ ̶c̶u̶r̶r̶e̶n̶t̶l̶y̶ ̶n̶o̶t̶ ̶w̶o̶r̶k̶i̶n̶g̶ ̶i̶n̶ ̶E̶x̶p̶o̶ ̶G̶o̶ ̶f̶o̶r̶ ̶A̶n̶d̶r̶o̶i̶d̶ ̶(̶d̶u̶e̶ ̶t̶o̶ ̶a̶ ̶r̶e̶g̶r̶e̶s̶s̶i̶o̶n̶ ̶i̶n̶ ̶R̶e̶a̶c̶t̶ ̶N̶a̶t̶i̶v̶e̶ ̶0̶.̶7̶2̶ ̶-̶ ̶s̶e̶e̶ ̶G̶i̶t̶H̶u̶b̶ ̶f̶o̶r̶ ̶c̶o̶n̶t̶e̶x̶t̶)̶. Update: this has been in the latest Expo Go on July 25, 2023.
  • “No ‘projectId’ found…” in expo-notifications getExpoPushTokenAsync (expo#23225). You can work around this by passing in the projectId as an option to the function.
  • There have been reports of eas update hanging after printing “Export was successful.” (eas-cli#1907). We have been unable to reproduce this, and we are currently investigating it.
  • n̶p̶x̶ ̶e̶x̶p̶o̶ ̶r̶u̶n̶:̶[̶a̶n̶d̶r̶o̶i̶d̶|̶i̶o̶s̶]̶ ̶i̶n̶ ̶a̶ ̶b̶a̶r̶e̶ ̶R̶e̶a̶c̶t̶ ̶N̶a̶t̶i̶v̶e̶ ̶0̶.̶7̶2̶ ̶p̶r̶o̶j̶e̶c̶t̶ ̶t̶h̶a̶t̶ ̶d̶o̶e̶s̶ ̶n̶o̶t̶ ̶e̶x̶t̶e̶n̶d̶@̶e̶x̶p̶o̶/̶m̶e̶t̶r̶o̶-̶c̶o̶n̶f̶i̶g̶ ̶i̶n̶ ̶m̶e̶t̶r̶o̶.̶c̶o̶n̶f̶i̶g̶.̶j̶s̶ ̶c̶u̶r̶r̶e̶n̶t̶l̶y̶ ̶w̶i̶l̶l̶ ̶f̶a̶i̶l̶ ̶t̶o̶ ̶b̶u̶n̶d̶l̶e̶.̶ ̶W̶e̶ ̶h̶a̶v̶e̶ ̶f̶o̶u̶n̶d̶ ̶t̶h̶e̶ ̶r̶o̶o̶t̶ ̶c̶a̶u̶s̶e̶,̶ ̶s̶e̶n̶t̶ ̶a̶ ̶p̶u̶l̶l̶ ̶r̶e̶q̶u̶e̶s̶t̶ ̶t̶o̶ ̶f̶a̶c̶e̶b̶o̶o̶k̶/̶r̶e̶a̶c̶t̶-̶n̶a̶t̶i̶v̶e̶,̶ ̶a̶n̶d̶ ̶t̶h̶e̶ ̶f̶i̶x̶ ̶i̶n̶ ̶r̶e̶a̶c̶t̶-̶n̶a̶t̶i̶v̶e̶@̶0̶.̶7̶2̶.̶2̶. Update: SDK 49 now uses [email protected] with this fix.
  • ̶r̶e̶a̶c̶t̶-̶n̶a̶t̶i̶v̶e̶-̶m̶a̶p̶s̶ ̶w̶i̶t̶h̶ ̶t̶h̶e̶ ̶s̶h̶o̶w̶s̶U̶s̶e̶r̶L̶o̶c̶a̶t̶i̶o̶n̶ ̶p̶r̶o̶p̶ ̶m̶a̶y̶ ̶c̶r̶a̶s̶h̶ ̶y̶o̶u̶r̶ ̶A̶n̶d̶r̶o̶i̶d̶ ̶a̶p̶p̶.̶ ̶Y̶o̶u̶ ̶c̶a̶n̶ ̶W̶e̶ ̶a̶r̶e̶ ̶i̶n̶v̶e̶s̶t̶i̶g̶a̶t̶i̶n̶g̶ ̶a̶ ̶f̶i̶x̶.̶ ̶Y̶o̶u̶ ̶c̶a̶n̶ ̶w̶o̶r̶k̶ ̶a̶r̶o̶u̶n̶d̶ ̶t̶h̶i̶s̶ ̶b̶y̶ ̶u̶s̶i̶n̶g̶ ̶r̶e̶a̶c̶t̶-̶n̶a̶t̶i̶v̶e̶-̶m̶a̶p̶s̶@̶~̶2̶.̶0̶.̶0̶-̶b̶e̶t̶a̶.̶1̶0̶ ̶i̶n̶ ̶t̶h̶e̶ ̶m̶e̶a̶n̶t̶i̶m̶e̶. Update: this has been resolved in expo-location v16.1.0 on Jul 13, 2023, and you can upgrade it in your app by running npx expo install --fix.

🧹 Dropped SDK 46; will drop SDK 47 and 48 next release

We routinely drop SDK versions that have low usage in order to reduce the number of versions we need to support. This release sees the end of life for SDK 46. This means that SDK 46 projects will no longer work within the latest version of Expo Go — and they will continue to work as expected otherwise.

Our next release will drop support for SDK 47 and 48. If your project is running on one of these releases, consider upgrading to a newer version soon.

➡️ Upgrading your app

Here’s how to upgrade your app to Expo SDK 49 from 48:

  • Update to the latest version of EAS CLI (if you use it):
    npm i -g eas-cli.
  • Install the new version of the Expo package:
    npm install expo@^49.0.0 or yarn add expo@^49.0.0
  • Upgrade all dependencies to match SDK 49:
    npx expo install --fix
  • Note: if you have expo-cli installed to your project dependencies, you will need to remove it! As of SDK 46, the CLI is now part of the expo package, and having the old expo-cli package installed may cause issues such as “error: unknown option --fix’” when running npx expo install --fix.
  • If you have any resolutions/overrides in your package.json, verify that they are still needed. You should remove metro and metro-resolver overrides to 0.76.0 if you added them for expo-router in SDK 48.
  • If you have @babel/plugin-proposal-export-namespace-from in your package.json dependencies, you can remove it. It is now included in babel-preset-expo.
  • Check for any possible issues in your project dependencies:
    npx expo-doctor@latest
  • Refer to the “Deprecations, renamings, and removals” section above for breaking changes that are most likely to impact your app.
  • Make sure to check the changelog for all other breaking changes!
  • Upgrade Xcode if needed: Xcode 14 is needed to compile the native iOS project. For EAS Build, projects without any specified image will default to Xcode 14.3.1.
  • If you manage your own native projects (bare workflow):
    — Run npx pod-install if you have an ios directory.
    — Apply any relevant changes from the React Native Upgrade Helper.
    — Alternatively, you could consider adopting prebuild for easier upgrades in the future.
  • If you maintain any Expo Modules for Android: refer to the Gradle 8 migration guide.
  • If you use Expo Go: Update the Expo Go app on your phones from app stores. Expo CLI will automatically update your apps in simulators. You can also download the iOS simulator build or the APK from expo.dev/tools.
  • If you use development builds with expo-dev-client: Create a new development build after upgrading.
  • Questions? We’ll be hosting some office hours focused on upgrading to SDK 49. Keep an eye out on Discord for more information / sign-ups.

Thanks to everyone who contributed to the release!

The team: everyone contributed one way or another, with special mentions to the engineers most directly involved in this release: Łukasz Kosmaty, Kudo Chien, and Tomasz Sapeta for leading all SDK work. Also, Aleksander Mikucki, Gabriel Donadel, Aman Mittal, Bartosz Kaszubowski, Cedric van Putten, Doug Lowder, Evan Bacon, Keith Kurak, Kim Brandwijk, Quin Jung, and Will Schurman. Welcome to the team, Alan Hughes, Wojciech Dróżdż, and Mark Lawlor! And lastly, thank you Wojciech Kozyra and Dominik Sokal for your contributions over the years, you will be missed!

External contributors: AB, Abdulah Proho, Adam Schlichtmann, Agustin Falco, Alberto, Alex Lin, Alexander Pataridze, Amir5000, Andrew Levy, André Ribeiro, Angad Sethi, Anindo Sarker, Anna Garcia, Aroyan, Augustine Ezeh, Bartłomiej Banasik, Basarat Ali Syed, BlessedOneKobo, Chee Kit, Daniel Friyia, David Leuliette, Desislav, DynamicApproach, Emmanuel Barat, Emmanuel C. Jemeni, Esteban Salazar, Eugene Nagorny, Felipe S. Santos, Fernando Rojo, Frederick Widjaja, Gianfrancø Null, Guilherme Santos, Gustavo Gard, HBiede, HarshaVardhanReddyDuvvuru, Hirbod, Hubert Gendron, Hugo FOYART, Jakov Glavina, James M, Joe Yanks, Joel Jaison, Jose Luis Paternina, Justice Ekemezie, Kazuma Ohashi, Kilian Finger, Kristaps Birziņš, LULU, Leandro Alberti, Linus Unnebäck, Logan Rosen, MJ Zhang, Mark Oswald, Marlon, Matin Zadeh Dolatabad, Max, Meenu Makkar, Niels Mokkenstorm, Paul Crussaire, RRaideRR, Robert Herber, Sara Tavares, Sergey Pashkevich, Silas, Sylers, Victor Li, Vikrant Bhat, Vittor Javidan, Vojtech Novak, William Théroux, Youssef Henna, Ziv Levy, abing, bigbend, bil9148, billybrown-iii, bouzuya, chalenascholl, jay shah, nishan, phoenixiguess, rcv4, sallen450, toshiyuki-suzuki-yukashikado, and 翊小久.

Beta testers: Danilo Polani, Benedikt, Mario Murrent, RRaideRR, Kyle G, Myroslav Hryhschenko, Timothy Shamilov, Eleftherios Myteletsis, Kaiden Sin, arasrezaei, Jun Matsushita, rvasseur31, Samuel Newman, Chee Kit, and many of the same folks listed above.

Thank you for reading — we hope you enjoy this release!