Expo SDK 50

Jan 18, 2024 by

Avatar of Brent Vatne

Brent Vatne

Today we're announcing the release of Expo SDK 50. SDK 50 includes React Native 0.73. Thank you to everyone who helped with beta testing.

SDK 50

Introducing Expo Dev Tools Plugins

This API provides a foundation for library authors (and adventurous app developers) to build browser-based plugins to debug and interact with aspects of their library / app. To validate and demonstrate the API, we also built a few plugins for popular tools: Apollo Client, TanStack Query, TinyBase, React Native Async Storage, and React Navigation — and you can find them in the expo/dev-plugins repository. Learn more.

This example app and the plugins used in it are available in: https://github.com/expo/dev-plugins

Thank you to everyone who provided feedback since our proof of concept release in August!

New and improved SQLite and Camera APIs

  • expo-sqlite/next: a complete re-write of our SQLite library, aimed to modernize the API and bring it towards parity with the mature equivalents that exist for web and Node.js. The API includes both sync and async methods, adds support for prepared statements, update callbacks, and the Blob data type, among other features! We've also updated the SQLite version to 3.42.0 on both platforms, rather than depending on the versions bundled with the operating system. This makes it possible to add support for SQLite extensions, such as CR-SQLite. We've also built a Knex dialect for expo-sqlite, for folks who like using query builders. SQLite is already an important building block and we believe that it will become increasingly more essential as patterns like local-first application architecture continue to grow, and we'll continue to invest in this library accordingly. Learn more about the new SQLite API.
  • expo-camera/next: accessing the device camera is a fundamental capability of many mobile apps, and we believe that this should be both simple to do and reliable. So, we've taken one of our older and most popular libraries and brought it up to date with native platform best practices. For most use cases, we expect expo-camera/next to fit like a glove. For more advanced use cases (such as frame processors), react-native-vision-camera is a fantastic option. Learn more about the new Camera API.
import { CameraView } from 'expo-camera/next';

// Minimal example of using the new API, refer to types for more information on props
export default function Camera() {
  return (
    <CameraView
      style={{ flex: 1 }}
    />
  );
}

Introducing @expo/fingerprint

This is our answer to a common question for React Native developers: “how do I know if an app JavaScript bundle is compatible with a particular build of my app?”.

The @expo/fingerprint CLI or API generates a fingerprint that represents the unique native characteristics of a project, and if that fingerprint changes, then you know that the JavaScript app that targeted the older fingerprint may be incompatible.

Try it out through the CLI: npx @expo/fingerprint path/to/your/project and learn more in the README, and in the expo-github-actions README. First class integration into EAS services will be coming in the future!

Example of running the @expo/fingerprint CLI

After you generate a fingerprint, try changing your project in a way that impacts your native runtime and use the CLI to compare it to find what changed. Learn more.

Expo Router v3

This is the next major release for universal file-based routing and advanced web support. Expo Router v3 includes many bugfixes and stability improvements, better documentation, web support, testing, and types. Most notably, Expo Router v3 now has experimental support for building universal server endpoints with API Routes. Learn more in "Expo Router v3: API Routes, bundle splitting, speed improvements, and more".

EAS Build

We continuously deploy improvements to EAS Build. Here are some of the highlights since the last SDK release:

  • Xcode 15.2 is now the default for macOS workers. Learn more.
  • JDK 17 and Ubuntu 20 are now the default for Linux workers. Learn more.
  • Node 18 is now the default. The default Node version on EAS Build tracks the current maintenance LTS, and on November 27th, 2023 we changed the default version from Node 16 to 18. Learn more.
  • Improved warnings and errors. "Build annotations" can make you feel like you have an experienced engineer looking over your shoulder to help you understand why you are seeing particular warnings and errors in your build, and what to do about them. Learn more.
  • Pre-warmed CocoaPods cache for faster builds. All of your iOS builds will be a bit faster, without any changes needed on your end. Learn more.
  • Expo Orbit v1 released: Orbit for macOS makes it faster and easier to install and run builds from EAS. Learn more.
  • ...we also added support for Bun, EAS CLI will now read .nvmrc files to set your Node version for your builds (unless explicitly specified in your build profile), eas build:run now accepts the --profile flag to filter builds, we added the eas build:delete command by request to support certain automation workflows, and we have continued improving the fully customizable builds preview which we hope to make GA in the coming months.

EAS Update

import { useUpdates } from 'expo-updates';

export default function App() {
  const {
    currentlyRunning,
    availableUpdate,
    isUpdateAvailable,
    isUpdatePending,
    // and so on!
  } = useUpdates();

  // etc..
}
  • New dashboard UI features: Recently we released some updates to the dashboard that allow you to: create new channels, remove them, republish updates, and remove them. Learn more
  • Rollbacks: It is now possible to instruct your production apps to roll back to their embedded update (the JavaScript app generated at build time) the next time they check for updates. This helps in cases where you accidentally deployed a regression as a first update to a new build, and you want to revert to the embedded working state rather than trying to deploy an update fix on top. Learn more.
  • Rollouts: You can now gradually roll out updates to a percentage of your users, in order to minimize the impact of accidentally introducing a bug to your production environment. Learn more.
A slider showing a rollout percentage of 25% for hotfix and 75% for production

First announced during our summer launch week, rollouts are now generally available for production use.

Basic Expo Modules support for tvOS and macOS

You can now use the Expo Modules API to build native modules for tvOS and macOS.

  • The use_expo_modules! method that autolinks Expo modules can now be used on tvOS and macOS targets in the Podfile. It automatically installs only these modules that declare support for the target platform in their podspec.
  • The packages supporting tvOS platform in SDK 50: expo-application, expo-av, expo-constants, expo-device, expo-file-system, expo-font, expo-image, expo-keep-awake, expo-localization, expo-splash-screen, expo-updates, @expo/cli. Learn more in the "Build Expo apps for TV" guide, and let us know which packages you are most interested in seeing supported in the future!
  • The packages supporting macOS platform in SDK 50: expo-constants, expo-file-system, expo-keep-awake (no-op). More packages will be adapted after the SDK release, and we'll also add support for @expo/cli so that you can use npx expo start to run your dev server. Let us know which packages you are most interested in!

Refer to the PR that installs Expo modules in Expo Orbit and the PR that migrates one of its native modules to Expo Modules API for examples. Documentation will be coming soon.

First-class Expo support in Sentry

sentry-expo has been merged into @sentry/react-native@5.16.0, and sentry-expo is now deprecated. The sentry-expo package will continue to work in SDK 50, but we recommend moving to @sentry/react-native. This change allows us to deduplicate efforts and ensure a better, always up to date experience for folks that use Sentry in their projects. A big thank you goes out to Krystof Woldrich from Sentry for his work on this!

While collaborating on this work, one of our goals was to improve the integration between Sentry and EAS Update. It is now as easy as eas update --branch <branch> && npx sentry-expo-upload-sourcemaps dist to publish an update and upload the corresponding sourcemaps.

Other Highlights

  • React Native 0.73 (latest at the time of writing) and React 18.2.0 (unchanged from SDK 49). There were many improvements in this release, refer to the React Native CHANGELOG, Release Notes, and React CHANGELOG for a complete account.
  • expo-font config plugin now supports natively adding fonts to your app. It can be useful to load fonts at runtime with Font.loadAsync or useFonts to avoid rebuilding your app binary, but fonts in an app typically don't change very much and so embedding the font into the native project with a config plugin can help you to clean up some of the async loading code from your app startup when you're ready to do a build. Learn more.
  • expo-secure-store gets a handful of new improvements. By popular demand, we've introduced synchronous getItem and setItem functions! We've also unified the behavior as much as possible across Android and iOS — other than different types of exceptions resulting from different native implementations, all of the functions now behave the same. This introduces a small breaking change — when fetching a value which doesn't exist in a keychain expo-secure-store will now always return null. Previously, Android would throw an exception and iOS would return null. Learn more about other changes in the changelog.
  • expo-dev-client now defaults to loading the most recently opened project when you boot up a development build. If the development server isn't available, then it falls back to the launch screen. We've heard that this is what people typically want when they boot a development build, but if this isn't your preference, then you can change this behavior with the config plugin:"launchModeExperimental": "launcher”. Learn more.
  • Added npx expo run command. Expo CLI will now prompt you to select a target platform if it's not explicitly named in the command. This is a small quality of life improvement that aligns the npx expo run UX with that of eas build:run. You can also use npx expo run android or npx expo run ios as alternatives to run:android and run:ios.
Terminal
npx expo run

? Select the platform to run › - Use arrow-keys. Return to submit.❯ Android iOS
  • npx expo install --fix now upgrades the expo package to the latest patch version. We have found that developers often keep up to date with Expo SDK patch versions released through an SDK cycle by running npx expo install --fix, with the exception of the expo package, which was not automatically updated with this command. We encourage developers to stay up to date with our latest patches, and so, after the initial upgrade to SDK 50, the --fix flag will update all of your Expo SDK packages, including the expo package.
  • Native project update tool now available. If you use CNG, this doesn't apply to you — although you may be curious to look at what is changing under the hood between releases. The React Native Upgrade Helper is a great tool for developers that are building projects on top of the React Native Community CLI template, but there are some differences in native projects that use this template as compared to projects that use Expo Modules. To make upgrading bare native projects with Expo Modules easier, we've built a similar tool to the community upgrade helper and it's now part of our docs: see the “Native project upgrade helper”.
  • Web bundle splitting with Metro, enabled by default. Yes, bundle splitting, with Metro! More information coming soon, for now, check out the related async routes documentation.
  • Improved error messages and code removal. Expo CLI now provides full stack traces for component-based errors, tree shakes all unused platform-specific code, and transforms faster when bundling for Hermes. Static website exports are now over 2x faster!
  • The URL and URLSearchParams standards are built-in. It was previously necessary to polyfill the web standard URL API (usually with the excellent react-native-url-polyfill library) in order to use many cross-platform libraries available on npm, where developers tend to assume that the URL API is available. We believe that URL is an important enough primitive that it deserves to be built in to the Expo core runtime, and so we now ship our own implementation in the expo package. Learn more.
  • Improved isolated modules support. You can now use pnpm or npm --install-mode=isolated for local development builds. For other scenarios, we're working through a few remaining blocking issues and hope to have an update soon.
  • Preview available of the experimental React Native JS debugger UI. We worked with Meta to unify the debugging experience in React Native as a whole, and the infrastructure that powers this new debugger UI is the same foundation as the JS debugger built into Expo CLI. The approaches are slightly different, and we'll talk about that more in the future.

You can try this debugger by setting EXPO_USE_UNSTABLE_DEBUGGER=1 when running npx expo start or npx expo run, and then launching the debugger from the CLI with j.

  • @expo/webpack-config is deprecated in favor of Expo CLI's Metro web. This means it that Webpack support will continue to work in SDK 50, but it will not be actively developed, and it will be removed in a future release. Read the "Webpack support in Expo CLI is now deprecated" blog for the full story, and learn about migrating away from Webpack to Metro.
  • CSS is enabled by default with Metro web. CSS is not supported on Android and iOS, but on web you can use all CSS features by importing CSS files. Learn more.
  • tsconfigPaths is now enabled in @expo/metro-config by default: this means that all you need to do to add path aliases is configure the paths property in your tsconfig.json. For example, "@/*": ["src/*"] will allow you to write code like import Button from '@/components/Button'; anywhere in your codebase and have it resolve to the correct location within src. Learn more.
  • Babel configuration changes in babel-preset-expo: we made a variety of small quality of life improvements in our Babel preset: we removed transforms that aren't necessary when targeting Hermes, we no longer alias react-native-vector-icons to @expo/vector-icons in the Babel preset (it's now done in the Metro resolver instead), and we now add the Reanimated plugin by default when it's installed (you don't need to remove it from your babel.config.js, but you may want to).
  • Bundler no longer starts automatically when running the app from Xcode. This aligns with the same change made in the React Native Community CLI template. Prior to running a build in Xcode (or afterwards, if you forget to do it before), run npx expo start to run the Expo dev server.
  • npx expo prebuild no longer executes [npm|yarn|pnpm|bun] install on each run by default. If no changes are made to the dependencies in the package.json (default when using the standard template) then the Node module installation step will be skipped. The only changes outside of the native directories will likely be the package.json scripts now.

Notable breaking changes

  • Android SDK 34, AGP 8, and Java 17. If you build your project locally, you will need to install JDK 17. Learn more.
  • Android minimum supported version bumped to Android 6 (API 23).
  • iOS minimum deployment target bumped to 13.4.
  • Expo CLI and React Native now require Node 18+. We also bumped the default Node version on EAS Build to Node 18 on November 27th.
  • Classic updates is no longer supported. As announced in February, 2023, projects using Expo SDK 50 do not support classic updates. We recommend EAS Update instead. Learn more.
  • @expo/vector-icons has been updated to use react-native-vector-icons@10.0.0: this adds support for FontAwesome6 and also changes to Ionicons and MaterialIcons. Most notably, the ios- and md- prefixed icon names in Ionicons have now dropped those prefixes. If you use TypeScript, you will be warned about any icon names that have changed when you update. Otherwise, be sure to verify that your icons are correct.
  • Most expo-updates JavaScript APIs are no longer available in Expo Go or development builds using expo-dev-client. The majority of the APIs exposed through the expo-updates JavaScript interface (for example, checkForUpdateAsync, fetchUpdateAsync, etc.) are designed to be used in production builds. In development builds, Expo Go and expo-dev-client control how updates are loaded in those environments.
  • React Native 0.73 changed from Java to Kotlin for Android Main* classes: MainApplication.java/MainActivity.java are now MainApplication.kt/MainActivity.kt. If you depend on any config plugins that use dangerous modifications to change these files, they may need to be updated for SDK 50 support.
  • The ProgressBarAndroid and ProgressViewIOS components from React Native have been removed in 0.73, after a long period of deprecation.
  • Refer to the Breaking Changes section of the Expo Router v3 post if you use it in your project.

🧹 Expo Go: Dropped SDK 47 and 48

We routinely drop SDK versions that have low usage in order to reduce the number of versions we need to support in Expo Go. This means that SDK 47 and 48 projects will no longer work within the latest version of Expo Go — and they will continue to work as expected otherwise. You can install older versions of Expo Go for Android device/emulators or iOS simulators, learn more.

A single SDK version per release of the Expo Go app: looking ahead to SDK 51

For years, Expo Go has supported multiple SDK versions in a single installation of the app (for example, Expo Go for SDK 49 supports SDK 47, 48, and 49 projects). We even have a patent for this approach: US Patent #11467854: “Method and apparatus for loading multiple differing versions of a native library into a native environment”. As you might imagine, there is a fair amount of work that goes into this for each SDK release — I'd go as far as to say that this is the single most tedious and difficult part of the release process.

At a time when development with Expo tooling was largely focused around Expo Go, this made a lot of sense for us to invest in. Expo Go was a stepping stone for us in our journey to building the Expo workflow as people know it today. The Expo Go app will continue to be a great sandbox to get started quickly and experiment with ideas, but we encourage adopting development builds for a flexible and powerful development environment suitable for real-world applications at scale.

We expect that including a single version of the Expo SDK in Expo Go will not have a large impact on most developers using Expo tools: Expo CLI will continue to install the appropriate version of Expo Go for the SDK that your project uses to any connected Android device/emulator or iOS simulator.

Let us know what you think about this upcoming change, and if you have any concerns about it: brent@expo.dev.

Known issues

➡️ Upgrading your app

Here's how to upgrade your app to Expo SDK 50 from 49:

  • Update to the latest version of EAS CLI (if you use it):
    Terminal
    npm i -g eas-cli
  • Install the new version of the Expo package:
    Terminal
    npm install expo@^50.0.0
  • Upgrade all dependencies to match SDK 50:
    Terminal
    npx expo install --fix
  • If you have any resolutions/overrides in your package.json, verify that they are still needed. For example, you should remove metro and metro-resolver overrides if you added them for expo-router in a previous SDK release.
  • Check for any possible known issues:
    Terminal
    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 15 is needed to compile the native iOS project. We recommend Xcode 15.2 for SDK 50. For EAS Build, projects without any specified image will default to Xcode 15.2.
  • If you use Expo Router: refer to the breaking changes in v3 and update your app accordingly.
  • If you don't use Continuous Native Generation:
  • If you maintain any Expo Modules:
    • For Android: update your library build.gradle to match the changes in this diff. You may also now remove the JVM target version configuration, as explained in this FYI page.
    • For iOS: update the platform deployment target field from '13.0' to '13.4', matching the changes in this diff.
  • If you maintain any config plugins:
    • Note that MainActivity.java and MainApplication.java were migrated to Kotlin. If you use any config plugins that modify these files, they may need to be updated for SDK 50 support (for example, this config plugin).
  • 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 an SDK 50 launch live-stream on January 31st, join us on YouTube.

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, Alan Hughes, Aleksander Mikucki, Gabriel Donadel, Aman Mittal, Bartosz Kaszubowski, Cedric van Putten, Doug Lowder, Evan Bacon, Keith Kurak, Kim Brandwijk, Quin Jung, Will Schurman, Wojciech Dróżdż, and Mark Lawlor. Welcome to the team, Kadi Kraman and Phil Pluckthun!

External contributors: Adnan Karšić, Ahmed Ali, Alexander Pataridze, Alfonso Curbelo, Ammar, Amr Hassaballah, Andrew Enyeart, Andrew X. Shah, Andy Matuschak, Anthony Mittaz, Antonio Dal Sie, Archimedes Trajano, Avi Avinav, Ayrton-Taede Tromp, Bartosz Boruta, Ben, Ben Limmer, Benny Neugebauer, Brad Cooley, Brad Jones, Brandon Austin, Brian Sharon, Chee Kit, Cho Chi Him, Claude, Colin McDonnell, Craig Malton, César Guadarrama, Daniel, Daniel Friyia, Daniel Reichhart, David Leuliette, Debabrata Batabyal, Derek W. Stavis, Felix Schindler, Francis, Frank Calise, Frederick Ros, Gabriel Porto, Gavin, Gennadiy, Greg Westneat, Guilherme Oenning, Göksenin Güngör, Hirbod, Ian Felix, Ian Martorell, Igor Adrov, Isaac Way, J. Lewis, Jabed Zaman, Jacob Marshall, James Edmonston, Janic Duplessis, Joel, Johan Holm, Jonatan E. Salas, Jonathan Ehwald, Joon Shakya, Josh Kramer, Joshua Joseph Myers, Jun Matsushita, Justin Kaufman, Justin Parker, KIM WOORAM, Kacper Kapuściak, Kelvin Choi, Kesha Antonov, Krzysztof Piaskowy, Liam Jones, Linus Unnebäck, Logan Rosen, Lucas Fronza, Luiz Henrique Souza, M.H.Pousti, Marek Lewandowski, Marius, Marius Gaciu, Mateus Craveiro, Matin Zadeh Dolatabad, Matt Polky, Mehrdad Moradi, Michael Hueter, Mo Javad, Mohit Yadav, Mustafa Shabib, Nelson Sousa, Nikhil, Niklas Haug, Omer Sabah, Ossi Siipola, Pavlo Hromov, Peter Ferguson, Peter Hasza, Peter Hägg, Pierre Zimmermann, Pieter De Baets, Piotr Szeremeta, Pranjal soni, RRaideRR, Randall71, Robert, Robert Trevethan, Rodolfo, Rohit Kumar Saini, Rui Ying, Sebastian Biallas, Sergey Pashkevich, Siarhei Haikou, Simen Bekkhus, Spencer Chang, Suvin Nimnaka, TJ Couch, Tag Howard, Tarun Chauhan, Thomas Mollard, Thor 雷神 Schaeff, Tim Etler, Tomas Ravinskas, Tomek Zawadzki, Trivikram Kamat, Valentin Vetter, Vojtech Novak, Wanderson Alves, Weykon, William, Youssouf EL AZIZI, Zach Nugent, Zayyan Faizal, bja34, ebrahimhassan121, italocoura87, jingpeng, jleprinc, kapobajza, la55u, noman, owen-duncan-snobel, rieg-ec, safesecurely, and sak2.

Beta testers: Gamote, Alex Fournier, Justin Parker, SmashBoy, Justin, Valerii Smirnov, Rodrigo Figueroa, Dimo Portenko, Matthieu Gicquel, Muhammad Usman, Achmad Kurnianto, Liam Malloy, Rifaldhi AW, Kief, Tomasz Żelawski, Mo Javad, Peter Ferguson, Shannon, evelant, Alexander Nanberg, Andrzej Hanusek, Sergei Vronskii, Chanphirom Sok, Kenneth Stark, Tony Chen, Benjamin Komen, and Chris Zubak-Skees.