Expo SDK 51

May 7, 2024 by

Avatar of Brent Vatne

Brent Vatne

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

SDK 51

New Architecture is rolling out in 2024!

SDK 51 and React Native 0.74 represent a huge step forward in rolling out the long-awaited New Architecture for React Native.

  • We have added support for "bridgeless", one of the pillars of the New Architecture, to nearly all Expo modules and the Expo Modules API.
  • We worked in close collaboration with the React Native team at Meta and developers in the React Native ecosystem to ensure there would be support for the New Architecture in many of the most commonly used packages on EAS Build.

Testing your app with the New Architecture

There is still work to do, but we've made some incredible progress so far this year and we think SDK 51 and React Native 0.74 is the time to test your apps with the New Architecture. With your help, we can enable the New Architecture by default in SDK 52.

That said, most apps will run into some issues when testing with the New Architecture today, but we encourage you to try and report your experience. Improvements will be arriving rapidly during the SDK 51 and React Native 0.74 cycle, so if your initial attempt isn't successful, you might want to create a branch that you can retry every couple weeks with the latest versions of every package.

New default project template and "Getting Started" flow

When you create a new project with npx create-expo-app, you will see our ✨renovated new project template✨! It includes common dependencies and configuration that most projects need, so you can hit the ground running.

Screenshots of the new template project

That's a lot of code to delete if you don't need it! That's why you can run npm run reset-project to remove all of the boilerplate code and start fresh.

We've also updated the "Getting Started" flow to make it easier to get started with Expo, whether you are dipping your toes in with Expo Go or diving in with development builds. We hope that these changes will make it easier for you to get started with Expo and to understand the different options available to you.

Screenshot of the Expo getting started guide

Choose your own adventure, we'll explain exactly how to get started.

"Next" Camera and SQLite APIs are now the defaults

expo-camera/next is now exported from expo-camera (learn more), and expo-sqlite/next is now exported from expo-sqlite (learn more). You can find the old versions at expo-camera/legacy and expo-sqlite/legacy during SDK 51, and they will be removed in SDK 52.

Please note that these are complete rewrites, and the APIs have changed significantly. So, if you want to first upgrade to SDK 51 and then migrate to the new API, you can start by updating your imports to the legacy imports.

// New APIs (SDK 50)
import { CameraView } from 'expo-camera/next';
import * as SQLite from 'expo-sqlite/next';

// New APIs (SDK 51): if you import the next packages in your app, update the
// imports to the following:
import { CameraView } from 'expo-camera';
import * as SQLite from 'expo-sqlite';

// Legacy APIs (SDK 50)
import { Camera } from 'expo-camera';
import * as SQLite from 'expo-sqlite';

// Legacy APIs (SDK 51): if you import the legacy packages in your app, update
// the imports to the following:
import { Camera } from 'expo-camera/legacy';
import * as SQLite from 'expo-sqlite/legacy';
  • To migrate to the new APIs, refer to the respective docs. While many of the props and function names remain the same, there are also a number of changes. For example, onBarCodeScanned is now named onBarcodeScanned in the new Camera API. Using TypeScript will also help you to catch these.
  • You can learn more about the motivation behind the new expo-camera API in the "expo-camera/next is ready for a close up" blog post.
  • The new Expo SQLite API is 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 is built on SQLite 3.45.3, includes both sync and async methods, makes it easy to import existing databases, adds support for prepared statements, update callbacks, the Blob data type, and providing custom build flags for SQLite, among other features. Learn more

Thank you to everybody who used these APIs during SDK 50 and gave us feedback!

Introducing expo-symbols

expo-symbols is currently an iOS-only package that provides access to the SF Symbols library, a collection of over 5000 icons with multiple weights, scales, and support for animations. Learn more.

Screenshot of the VSCode with SF Symbols autocompletion and rendering in a simulator

Autocompletion with TypeScript makes it easy to find the right symbol for expo-symbols.

Fingerprint runtime version policy promoted from experimental to beta

By using the "runtimeVersion": { "policy": "fingerprint" } field in your app.json, you can be confident that your updates will always target compatible native runtimes. This makes @expo/fingerprint integration with EAS Build and Update seamless — you will notice, for example, that there is now a "Calculate expo-updates runtime version" step on builds for projects that use updates. Learn more about how this helps you to achieve Continuous Deployment, and learn about how @expo/fingerprint works.

Expo Router v3.5

Most of the user-facing changes in the latest release of Expo Router are bug fixes and improvements based on feedback from the community. We'll be sharing more in-depth blog posts about the new features and improvements in Expo Router v3.5 in the coming weeks. Some notable changes include:

  • Support for the # segment in URLs with const { "#": hash } = useLocalSearchParams().
  • Added new router functions for dismissing routes router.dismiss(), .dismissAll() and .canDismiss().
  • Removed ExpoRequest and ExpoResponse objects in favor of built-in WinterCG-compliant Request/Response objects.
  • Support for platform specific extensions for routes and _layout files (a platform agnostic version is still required).
  • Support to handle rewriting deeplinked URLs.
  • Improvements to Typed Routes.
  • Href in typed routes is no longer generic.
  • Fixes issues for experiments.baseUrl support on web.

Be sure to catch our talks at React Conf and App.js Conf for more information about what we have been working on in Expo Router!

Apple Privacy Manifests

Starting on May 1, Apple requires that apps using any "restricted reason" APIs include a privacy manifest. To make this easy for you to comply with, we have added support for the privacy manifest to the Expo config. Learn more.

app.json
{
  "expo": {
    "ios": {
      "privacyManifests": {
        "NSPrivacyAccessedAPITypes": [
          {
            "NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategoryUserDefaults",
            "NSPrivacyAccessedAPITypeReasons": ["CA92.1"]
          }
        ]
      }
    }
  }
}

We also contributed a feature to React Native that adds support for automatically aggregating privacy manifests from CocoaPods resource bundles. This feature is available in React Native 0.74.1, but there are some edge cases that are not yet supported, so we have temporarily disabled it by default in SDK 51 projects.

For now, we recommend using the Expo config to add privacy manifest configuration for your dependencies. Once a new React Native release is available with fixes for the edge cases, we will enable the aggregation feature by default. If you'd like to try it now, you can opt-in by setting ios.privacyManifestAggregationEnabled to true in the expo-build-properties config plugin. Bare projects can set this value directly in the Podfile.

EAS Update: rollout web UI and new preview page

In SDK 50, we released support for "rollouts": this allows you to 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. This was previously only available in EAS CLI, and we've now released an intuitive web UI to create and manage rollouts more easily.

Example of a rollout in the EAS Update web UI

Select a deployment from the deployments page for your project (in the left sidebar), and from there you can create a new rollout or manage existing rollouts. In this case, we're rolling out the "preview" branch to 10% of users. We can come back and adjust it later if it all goes well, or delete the rollout if it doesn't.

We've also revamped our web UI for opening and sharing updates with your team. Press the "Preview" button on the top right of an Update details page to open the preview modal.

Notice the integration with Orbit, and the list of compatible development builds. When you scroll down, you will find a shareable URL you can copy to send to your team.

🧹 Expo Go: Dropped SDK 49 and 50

The Play Store / App Store versions of Expo Go now only support SDK 51. If you have a project that uses SDK 49 or 50, you can still use Expo CLI or expo.dev/go to install the appropriate version of Expo Go for your project.

Single SDK version in Expo Go

As announced in SDK 50, starting with SDK 51, Expo Go will only support a single SDK version at a time. This means that when the new Expo Go version supporting SDK 51 is released to the App Store and Play Store, it will only support SDK 51. It will not support SDK 50 or below. 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.

To make it as easy as possible to install a specific version of Expo Go, created expo.dev/go, a website that makes it as easy as possible to install a compatible version of Expo Go on your target platform. This works on Android devices/emulators and iOS simulators, but due to limitations of the iOS platform, you will only be able to use the latest version of Expo Go on physical iOS devices.

expo.dev/go makes it easy to install a compatible version of Expo Go on your target platform. The error message that you see when you try to open a project with an unsupported SDK version in Expo Go links directly to this website with the appropriate version and platform selected.

Other Highlights

  • Beta release of new expo-video library. Following the success of the "next" Camera and SQLite APIs, we are releasing a new video library that incorporates our learnings from maintaining expo-av over the years. This library is a complete rewrite of the Video functionality from expo-av, and it's designed to be more reliable and easier to use. We expect to update this library frequently during the SDK 51 cycle, and so it will not yet be available in Expo Go (yet another reason to use Development Builds). Learn more.

  • eslint-config-expo and npx expo lint command: You can now run npx expo lint in your project to generate an ESLint config file that extends from eslint-config-expo. The philosophy of this config is to focus on code correctness and avoid stylistic rules that can be subjective. More documentation is coming soon, until then you can read the rules in the source code.

    # When ESLint is not configured yet
    npx expo lint
    ? No ESLint config found. Install and configure ESLint in this project? › (Y/n)
    
    # After ESLint has been configured
    npx expo lint
    > yarn eslint .
    $ /app/node_modules/.bin/eslint .
    
    /app/components/HelloWave.tsx
      22:6  warning  React Hook useEffect has a missing dependency: 'rotateAnimation'. Either include it or remove the dependency array  react-hooks/exhaustive-deps
    
    ✖ 1 problem (0 errors, 1 warning)
    
  • expo-asset config plugin makes it easy to link assets as native resources. This is useful for linking assets that need to be accessed by native code that expect resource names, or to include assets without needing to modify the Metro configuration. Learn more.

  • Modernized library build.gradle. If you maintain an Expo module, you don't need to change anything; but, if you want to clean your module up a bit, you can apply the changes from this diff. Learn more about the changes in expo/expo#28083.

  • Bundler speed improvements: EXPO_USE_FAST_RESOLVER=1 can be set to enable up to 6x faster Metro resolution. We've also fully removed "exotic" bundling in favor of the default expo/metro-config which has fully integrated stable speed improvements. Learn more

  • Expo CLI supports running on iOS devices over the network and for Vision Pro simulators. Use npx expo run:ios --device to pick a device from the list of available devices on your network, in the same way you would from the device selection window in Xcode.

    npx expo run:ios --device
    ? Select a device ›
    ❯   🌐 Brent iPhone (17.4.1)
        🌐 Apple Vision Pro (1.1.1)
        iPhone 15 (17.4)
        iPhone 15 Plus (17.4)
      ↓ iPad Pro (12.9-inch) (6th generation) (17.4)
  • Create Expo (App) now supports all mainstream package managers and versions. Whether you're using Yarn, pnpm, Bun, or npm, create-expo/create-expo-app will initialize a project with the required configuration to ensure that it will work with your package manager of choice.

    🗄️ npx create-expo-app@latest
    🌭 bunx create-expo-app
    📦 pnpm create expo-app
    🧶 yarn create expo-app
  • Expo Orbit for Windows is available in beta. One click to download, install, and run your apps, now for Windows too! Try it out and give us feedback. Learn more.

  • EAS Build default worker image for iOS builds now uses macOS 14.4 and Xcode 15.3 Learn more.

  • React Native 0.74 and React 18.2.0 (unchanged from SDK 50). There were many improvements in this release, so refer to the React Native CHANGELOG, and Release Notes. One change that many folks will be excited about is that Yoga has been upgraded to 3.0, which improves layout correctness and adds support for two additional layout properties. You may also be able to drop a few polyfills: TextEncoder, btoa, atob are now globally available in Hermes.

Deprecations, renamings, and removals

  • expo-camera imports have changed: if you want to continue using the legacy implementation, update your imports from expo-camera to expo-camera/legacy. If you were already using the "next" implementation, then update the imports from expo-camera/next to expo-camera. The legacy implementation will be available until SDK 52.
  • expo-sqlite imports have changed: if you want to continue using the legacy implementation, update your imports from expo-sqlite to expo-sqlite/legacy. If you were already using the "next" implementation, then update the imports from expo-sqlite/next to expo-sqlite. The legacy implementation will be available until SDK 52.
  • Fingerprint runtime version policy has been renamed: "runtimeVersion": { "policy": "fingerprintExperimental" }"runtimeVersion": { "policy": "fingerprint" } in your app.json.
  • The hooks field has been removed from app.json: this was previously used for the Classic Updates and sentry-expo, which was deprecated in SDK 50 in favor of @sentry/react-native. You should remove the hooks field from your app config.
  • sentry-expo is no longer supported, use @sentry/react-native instead. In SDK 50, sentry-expo was deprecated in favor of @sentry/react-native, which we worked closely with the Sentry team on to ensure first-class support for Expo projects. Learn more.
  • Expo Go only supports a single SDK version as of SDK 51. Learn more.
  • Google Maps is no longer supported in Expo Go for iOS. You can use Apple Maps in Expo Go instead (remove the prop provider={PROVIDER_GOOGLE} from your <MapView /> components) or switch to a development build (recommended). If you have already configured Google Maps for your production releases, no additional configuration will be necessary. Learn how to set up a development build.
  • Foreground location service is no longer supported in Expo Go for Android. You can use it in a development build, enable the isAndroidForegroundServiceEnabled option in the config plugin.
  • Notifications entitlement is no longer always added to iOS projects during prebuild: No changes are required if you use expo-notifications. If your project uses push notifications but does not use the expo-notifications package, you may need to add the aps-environment entitlement to your app config:
    app.json
    {
      "expo": {
        "ios": {
          "entitlements": {
            "aps-environment": "development"
          }
        }
      }
    }
    

Known issues

  • Resolved in Expo Go v2.31.5. Expo Router may crash in SDK 51 when switching tabs (related issue)...
  • Resolved in expo-updates@0.25.14. If you have expo-updates installed in your app, you will need to have runtimeVersion configured to load it in a development build.
  • react-native-dotenv is not compatible with expo-router. If you are using the react-native-dotenv Babel plugin, it will overwrite expo-router configuration environment variables and you'll see the empty state "Welcome to Expo" screen. We are tracking the incomptibility in expo/expo#28933, but we recommend removing the library and Babel plugin, and instead using Expo CLI's built-in support for .env files (learn more).
  • Found an issue? Report a regression.

➡️ Upgrading your app

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

  • Update to the latest version of EAS CLI (if you use it):

    Terminal
    npm i -g eas-cli
  • Upgrade all dependencies to match SDK 51:

    Terminal
    npx expo install expo@^51.0.0 --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.3 for SDK 51. For EAS Build, projects without any specified image will default to Xcode 15.3.

  • If you don't use Continuous Native Generation:

  • If you maintain any Expo Modules: it is optional, but you may want to modernize your library build.gradle by applying the changes from this diff. Learn more about the changes in expo/expo#28083.

  • 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/go.

  • If you use development builds with expo-dev-client: Create a new development build after upgrading.

  • Questions? Join our weekly office hours on Wednesdays at 12:00PM Pacific. Register for Expo Office Hours.

📺 Tune in to upcoming conferences for more news!

  • React Conf: the official React Conference from Meta, May 15-16. Expo team members Evan Bacon and Kadi Kraman will be speaking, alongside many other great speakers. Learn more.
  • App.js Conf: a React Native & Expo conference organized by our friends and colleagues at Software Mansion, May 22-24. In all but name, it's the official Expo conference. Learn more.

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, Kadi Kraman, Aman Mittal, Bartosz Kaszubowski, Cedric van Putten, Doug Lowder, Evan Bacon, Keith Kurak, Kim Brandwijk, Quin Jung, Will Schurman, Wojciech Dróżdż, Mark Lawlor, and Phil Pluckthun!

External contributors: Adrian Drummond, Adrien Jacquier Bret, Albert Schilling, Alejandro Paredes Alva, Alex Fournier, Alex Ownejazayeri, Alexander Pataridze, Alperen Gözüm, Alpheus, Amir Angel, Andreas K, Andrew McCallum, Angel S. Moreno, Aprilia, ArianHamdi, Aroyan, Baraa Bilal, Benny Neugebauer, Brandon Orther, Brandon Pelton-Cox, C. L. Jones, Charles Kornoelje, Christian, Colton Schlosser, Cyril Bonaccini, Daniel Lindenkreuz, Daniel O'Neill, Dat Nguyen, David Jebing, David Storm, Derek Guenther, Divy Srivastava, Dmitry Litsman, Dominic Go, Dylan, Fabrizio Codello, Frank Calise, GaelCO, Hailey, Harsh Mangalam, Hichem Fantar, Hirbod, Howard Dean Watts, Humberto, Ian Felix, Ibukun Olofin, Jacek Pudysz, Jackson Ludwig, Jake Zhao, Jakov Glavina, Jakub T. Jankiewicz, James Sigurdarson, Jamie Birch, Jan Richter, Jarren San Jose, Jens Tschirpig, Jonathan Walker, JongHan Leem, Jorens Merenjanu, Josh, Jover, Jun Matsushita, Kamil Owczarz, Kevin J Gao, Kryštof Woldřich, Leon, Lukas, Manoel Aranda Neto, Mark Rickert, Markus Kurzmann, Mathieu Acthernoene, Mathieu Post, Maximilian Vitzthum, Med Daifi, Mike Hamilton, Mike Kruk, Muhammad Bilal, Nathan Ahn, Nikita Dudin, Otto Bretz, Patrick Weisensee, Pavlos Vinieratos, Peter Jozsa, René Klomp, Riza Hassan, Rodolfo Perottoni, Roman Kubiv, Rui Ying, Sam Carlton, Seth Lachman, SeungRyeol Lee, Stefano Martella, Stephen Kempin, TN531, Thibault Malbranche, TomOConnor95, Utyfua, Vojtech Novak, Yousef Abu Shanab, benjamin, dan, ericKuang, gabimoncha, gkasdorf, jack, jay shah, katayama8000, lukben2000, mkhoussid, nishan, p16w, pga32ah, ppichier, raph, scottwoodall, tess-dev-main, ts-candide, waiscodes, and 風魔小次郎.

Beta testers: Michał Rusinek, Oscar Landmark, RRaideRR, Kryspin Ziemski, Costas Ioannou, nam-aalto, FightFarewellFearless, contactsimonwilson, NadeemKhanFh, Nathan Bird, Mike Hamilton, and Austin Harris.