Expo SDK 54 beta is now available

Aug 19, 2025 by

Alan Hughes

Alan Hughes

Brent Vatne

Brent Vatne

SDK 54 Beta

The SDK 54 beta period begins today and will last approximately two weeks. The beta is an opportunity for developers to test out the SDK and ensure that the new release does not introduce any regressions for their particular systems and app configurations. We will be continuously releasing fixes and improvements during the beta period — some of these may include breaking changes.

SDK 54 beta includes React Native 0.81 and React 19.1.0. The full release notes for SDK 54 won't be available until the stable release, but you can browse the changelogs in the expo/expo repository to learn more about the scope of the release and any breaking changes. We'll merge all changelogs into the root CHANGELOG.md when the beta is complete.

We're also hosting office hours on Discord for those of you interested in helping test the release!

Precompiled React Native for iOS

Starting with React Native 0.81 and Expo SDK 54, React Native on iOS and its dependencies will be shipped as precompiled XCFrameworks alongside the source.

We’ve found that [using the precompiled XCFrameworks] reduced clean build times for RNTester from about 120 seconds to 10 seconds (on an M4 Max — exact numbers will vary depending on your machine specs). While you’re unlikely to see a ~10x build time improvement in your app due to the number of other dependencies in most apps that will still need to be compiled, we expect a noticeable reduction in build times in large projects and an even more pronounced improvement in smaller projects where React Native is responsible for a greater share of the build time.

In addition to the speed benefits, this improvement brings us closer to being able to move from CocoaPods to Swift Package Manager for React Native and Expo projects.

Note: in React Native 0.81.0, apps that are compiled in Release using the precompiled XCFrameworks can’t be submitted to the store, but this will be resolved in 0.81.1, which will be available during the week of August 25. In the meantime, if you’d like to submit a build to TestFlight you can disable this behavior with expo-build-properties by setting ios.buildReactNativeFromSource to false.

Learn more in Precompiled React Native for iOS: Faster builds are coming in 0.81.

iOS 26 and Liquid Glass

Support for Liquid Glass icons and Icon Composer

SDK 54 adds support for iOS 26 Liquid Glass icons, which you can create using the new Icon Composer app. The Icon Composer app produces a .icon file, which you can reference in your app.json under the ios.icon key:

app.json
{
"ios": {
"icon": "./assets/app.icon"
},
"android": {
"adaptiveIcon": {
...
}
}
}


It’s important to note that the Icon Composer app is macOS only — if you don’t have access to a macOS machine that can run the app, then you won’t be able to take advantage of the UI for building the icons. However, the output is relatively straightforward JSON and it’s possible that a tool will emerge to handle this.

When your app using this icon format is run on an older iOS version (iOS ≤ 19), an appropriate fallback will be automatically provided by the operating system.

Liquid Glass Swift UI modifier and button variant

Expo UI for iOS is now in beta, and this includes support for Liquid Glass modifiers and button variants. Documentation coming soon — for now, refer to the examples below and the TypeScript types. Note that you must compile your app with Xcode 26 and run it on iOS 26 in order to use these features. To give it a try, copy and paste the code from this Gist into your app.

See these effects live on this YouTube short. Also notice the iOS 26 bottom tabs UI — this is available in Expo Router v6. See the Expo Router section below for more information.

Code
import { Host, HStack, Text } from "@expo/ui/swift-ui";
import { glassEffect, padding } from '@expo/ui/swift-ui/modifiers';
// In your component
<Host matchContents>
<HStack
alignment='center'
modifiers={[
padding({
all: 16,
}),
glassEffect({
glass: {
variant: 'regular',
},
}),
]}>
<Text>Regular glass effect</Text>
</HStack>
</Host>
Code
import { Button, Host, VStack } from "@expo/ui/swift-ui";
// In your component
<Host matchContents>
<VStack spacing={8}>
<Button
variant="glassProminent"
color="orange"
systemImage="questionmark.circle"
>
Help & support
</Button>
<Button variant="glass" systemImage="person">
View profile
</Button>
</VStack>
</Host>

Coming soon during the beta: glass container effects

We’re working on making GlassContainerEffect available in Expo UI, and we expect this to be ready for testing soon during the beta period.

Xcode 26 beta support available on EAS

You can opt in to using Xcode 26 beta on EAS Build by setting the image on your build profile to macos-sequoia-15.5-xcode-26.0. This is required if you plan to take advantage of the above iOS 26 related features.

React Native for Android now targets Android 16 / API 36

Edge-to-edge is now always enabled

With Expo SDK 54 and React Native 0.81 now targeting Android 16, edge-to-edge will be enabled in all Android apps, and cannot be disabled. Additionally, react-native-edge-to-edge is no longer a dependency of the expo package because the required functionality was built into React Native by the author of the library, Mathieu Acthernoene. If you are using the react-native-edge-to-edge config plugin to configure edge-to-edge in your project, make sure that the package is a direct dependency of your project (npx expo install react-native-edge-to-edge). If you were only using the plugin only to configure the enforceNavigationBarContrast option you can use the new androidNavigationBar.enforceContrast property in your app.json to get the same effect without additional dependencies.

Predictive back gesture enabled by default in new projects

The Android predictive back gesture feature is enabled by default on new projects, and disabled by default on existing projects. You can enable or disable the property in your app.json with android.predictiveBackGestureEnabled. Similar to edge-to-edge, we expect opt-outs will eventually be removed from a future version of Android, and we plan to enable this by default in all projects in SDK 55. Learn more.

Expo Updates & EAS Update

  • The HTTP headers Update sends, such as channel, can now be overridden at runtime with Updates.setUpdateRequestHeadersOverride(). This enables developers to easily implement patterns such as opting employees into a different update channel than end-users. Unlike Updates.setUpdateURLAndRequestHeadersOverride() , which allows you to also override the update URL and requires the disableAntiBrickingMeasures build time flag — the new method only applies to headers, is available without setting any flags, and can be used safely in production apps. Configuration set with either method will apply immediately to the currently running app. This means that you don’t need to restart the app for the new configuration to take effect, you can call Updates.fetchUpdateAsync() and Updates.reloadAsync() after you update the headers. Learn more about overriding request headers.
  • The useUpdates() hook now includes a downloadProgress property, which you can use to track the progress of asset downloads during an update. You can use this to show a progress bar when downloading an update, and possibly other creative scenarios. Learn more.
  • Updates.reloadAsync() now accepts reloadScreenOptions to give developers control over the UI that is presented while your app is reloading. This provides a much better user experience than a flash of empty content. In development, you can test your reload screen configuration by using Updates.showReloadScreen({ screenReloadOptions }) and Updates.hideReloadScreen(). The following example configuration shows a full screen image and fades out when the update has been applied:
Code
import * as Updates from 'expo-updates';
Updates.reloadAsync({
reloadScreenOptions: {
backgroundColor: '#fa0000',
image: require('./assets/images/reload.jpg'),
imageResizeMode: 'cover',
imageFullScreen: true,
fade: true
},
});
  • React Native modules that are installed as transitive dependencies will now be autolinked. While Expo Autolinking always worked this way for Expo modules, now that we take care of linking React Native modules (as of SDK 52) we were able to implement this behavior for React Native modules as well. This means that you will be able to let libraries take care of managing their dependencies, rather than copying and pasting a command to install a handful of native dependencies on their behalf (learn more). You can revert back to the previous autolinking behavior, by adding the expo.autolinking.legacy_shallowReactNativeLinking: true flag in your app’s package.json.
  • Expo and React Native modules will now link according to your app’s direct and nested dependencies, rather than the former behavior of autolinking any module in your node_modules that includes expo-module.config.json. This is primarily relevant to monorepos, where dependencies from multiple apps may be hoisted to the same node_modules directory. Now, either your app or a dependency of your app will need to contain a native module in their dependencies or peerDependencies for it to be linked. You can revert back to the previous autolinking behavior by adding your node_modules folders to expo.autolinking.searchPaths in your app’s package.json.
  • Expo Autolinking now has unified behavior across Expo and React Native modules, and so it will behave more predictably with isolated dependency installations (Bun and pnpm) and with hoisting conflicts.

Changes that impact how dependencies are handled will often lead to issues in more unique project configurations that couldn’t be anticipated. You can verify your expected native modules against the output of npx expo-modules-autolinking verify -v proactively or to troubleshoot issues if you believe they may be related to these changes. If you need to opt out of both of the changes mentioned above, add the following to your app’s package.json:

Code
{
"expo": {
"autolinking": {
"legacy_shallowReactNativeLinking": true,
"searchPaths": ["../../node_modules", "node_modules"]
}
}
}

SDK 54 is the final release to include Legacy Architecture support

In React Native 0.80, the React Native team introduced a code freeze on the Legacy Architecture. In React Native 0.82, it will no longer be possible to opt out of the new architecture. This means that SDK 55, which will likely include React Native 0.83, only support the New Architecture.

In recent months, a growing number of libraries have started to only support the new architecture. For example: react-native-reanimated v4 and @shopify/flash-list v2. The interop layer will remain a part of React Native for the foreseeable future, in order to ensure that libraries built for the Legacy Architecture continue to work well in modern apps.

At the time of writing, 75% of SDK 53 projects built on EAS use the New Architecture. If you are still concerned about migrating, learn more about work that has been done to address the last remaining identified issues found while migrating some of the largest React Native apps.

Highlights

  • React Native 0.81 with React 19.1. Refer to the release notes for React Native 0.81 and React 19.1 changelog for detailed information. (other info here). Also, learn more about the Expo SDK policy for tracking React Native versions.
  • expo-file-system/next is stable: The new expo-file-system API is now stable and exposed as a default. If you were using it prior to upgrading, you will need to update your imports from expo-file-system/nextexpo-file-system. The old API is still available under expo-file-system/legacy. Some improvements include: an object-oriented API for working with files and directories, support SAF URIs on Android and bundled assets on both iOS and Android. You can expect more information in an upcoming blog post, in the meantime you can refer to the API reference.
  • expo-sqlite now includes a drop-in implementation for the localStorage web API. If you're already familiar with this API from the web, or you would like to be able to share storage code between web and other platforms, this may be useful. Learn how to import and install the localStorage API.
  • Prebuild template now included in the expo package rather than downloaded from npm. This ensures that the template used by a given expo package version remains unchanged even if new template versions are released. Updating the expo package will also bring in a new template version. Thanks to Thibault Malbranche for suggesting this change. Note that you can still provide a custom prebuild template with the --template flag.
  • expo-sqlite added loadExtensionAsync() and loadExtensionSync() APIs to support loading SQLite extensions. The sqlite-vec extension, which supports vector data processing, is also bundled to expo-sqlite as an opt-in extension. You can use sqlite-vec for some RAG AI work. See the implementation in expo#38693, for loadExtensionAsync() API usage, the withSQLiteVecExtension config-plugin option to opt-in sqlite-vec.
  • expo-app-integrity: New package for verifying app integrity using DeviceCheck (DCAppAttestService) on iOS and the Play Integrity API on Android. This allows you to confirm that the app is installed via the App Store or Play Store and is running on a genuine, untampered device. Documentation coming soon. The package is currently named @expo/app-integrity but we intend to move it to expo-app-integrity when we have access to the package. Learn more about the API.
  • expo/blob: New package for working with binary large objects on iOS and Android. Our implementation is consistent with the W3C specification, providing you with interfaces familiar from the web. expo-blob is now in beta, and we’re excited to get your feedback! This library is not yet included in Expo Go. Learn more.
  • expo-maps: Added support for JSON and Google Cloud based map ID styling on Google Maps and Points of Interest (POI) filtering on Apple maps. Learn more.
  • expo-dev-launcher rewrite: we rebuilt the expo-dev-client UI in order to simplify the interface with React Native and improve the Hermes debugging experience. In doing so, we also made some other improvements to the look and feel — let us know what you think!

Apple and Android TV

  • Experimental expo-dev-client support for Apple TV, full support on Android TV. Support on tvOS is still early, and you can’t yet authenticate with your Expo account in the app, but give it a try if you have an Apple TV and let us know what you think.
  • Added support for Apple TV in various SDK packages: expo-sqlite, expo-background-task, expo-task-manager, expo-insights, expo-image-loader, expo-image-manipulator, and expo-video-thumbnails. See the doc pages for the individual packages for more details.
  • tvOS builds will leverage the new precompiled frameworks provided in React Native 0.81: This will significantly reduce build times for these platforms (related blog).

Expo CLI

  • Import stack traces are now enabled by default. You can now see a list of imports leading to a missing module which makes it much easier to trace broken packages. With this feature, we found agents (such as claude code) could always resolve broken imports.
  • experimentalImportSupport is now enabled by default. We’ve rebuilt Metro import support in Expo CLI to better support React Compiler, and tree shaking. This moves us one step closer to full ESM support in Expo. You can revert to the older system by setting experimentalImportSupport: false in the metro.config.js. We plan to remove this flag altogether in the next SDK release. The rebuilt support uses live bindings by default to improve compatibility with a wide range of projects. If you don't want this, set EXPO_UNSTABLE_LIVE_BINDINGS=false. Note that disabling live bindings might cause issues, especially if import cycles are present in your codebase.
  • Expo CLI now auto-prefixes CSS by default using the Rust-based lightningcss. You can remove autoprefixer from your postcss.config.mjs file in favor of this implementation. We’ve also added support for browserslist in the package.json. Learn more.
  • @babel/plugin-transform-class-static-block is now added to babel-preset-expo by default. This enables an even wider set of web and server libraries to work with Expo by default. Learn more about static class blocks.
  • React Compiler is now enabled in the default template. We recommend using it in your projects. The Meta team is actively fielding support for any remaining issues with React Compiler. You can see which components are memoized by pressing J in Expo CLI and going to the components panel. You will see “Experimental React Compiler is enabled.” printed in your logs when you run npx expo start — this is because it is currently in Release Candidate. However, we believe it is ready for most apps. This default may change if this proves false during the beta period. Learn more in the Expo + React Compiler docs.
  • React Native owner stacks are now enabled by default. These improve errors that occur in React components and make it easier to find/fix problems for both humans and agents.
  • Unhandled promise rejections are now logged as errors. After upgrading to this SDK, you might notice new promise rejection errors in your mobile applications. These aren't caused by the SDK itself, but are now properly surfaced as errors, which aligns with how Promises work in web browsers.
  • Experimental autolinking resolution was added. Expo CLI is now able to apply Expo Autolinking’s linking decisions to JavaScript module resolution (also known as “sticky resolution”). This prevents mismatches between native modules and JavaScript modules, even in the presence of dependency conflicts and duplicates. Set EXPO_USE_STICKY_RESOLVER=1 to test this.

Expo Router

Expo Router v6 - Link Previews
  • Link now supports iOS view controller previews, transitions, and context menu items. These can be used to add quick actions and information to any link in your app. Learn more.
  • Beta support for native tabs on iOS and Android. Unlike the JS tabs implementation, this enables liquid glass tabs, automatic scrolling on tab press, and many other beautiful native effects. The API is still under development and subject to breaking changes until we remove the unstable- prefix from the import. Learn more.
  • Modals on web now emulate iPad and iPhone behavior instead of just being a full screen page with no modal-like attributes.
  • New experimental server middleware support. Middleware can be used to run code before requests reach a route. Learn more.
  • TextDecoderStream and TextEncoderStream are added to the native runtime to better support fetch streaming and working with AI.

Deprecations

  • expo-build-properties field enableProguardInReleaseBuilds is deprecated in favor of enableMinifyInReleaseBuilds.
  • React Native’s <SafeAreaView> component has been deprecated: use react-native-safe-area-context instead if you aren’t already. It’s a much more powerful alternative, and one of those libraries that nearly every app uses.
  • The notification configuration field in app config has been deprecated in favor of expo-notifications config plugin.

Notable breaking changes

  • First-party JSC support removed from React Native: React Native 0.81 no longer provides built-in JSC support — if you would like to continue using JSC, refer to https://github.com/react-native-community/javascriptcore. Note: this community-maintained JSC library does not yet provide a config plugin, and so you will need to either write your own or modify your native projects directly in order to use it.
  • Reanimated v4 introduces react-native-worklets, only supports the New Architecture, and more. Refer to the Reanimated 3.x to 4.x migration guide — but skip modifying your babel.config.js - configuring this will be taken care of for you by babel-preset-expo. If you need to continue using the Legacy Architecture for now, you can continue using v3 — learn more. Additionally, if you use Nativewind then you will need to remain on Reanimated v3 because it does not yet support v4.
  • Internal Metro imports have changed in metro@0.83 (the version that is used by React Native 0.81). Importing internal code from any Metro package through metro/src/.. is not recommended anymore. To emphasize that nested paths are internal, not covered by semver and may change at any point in time, they must now be written as metro/private/.. instead. For most app developers, this won’t impact you. However, if you are using a library that imports Metro internals, then you may see errors related to Metro import paths — if so, try updating that library to the latest version and post an issue on their GitHub repository if that does not resolve it.
  • expo-file-system legacy API now available through expo-file-system/legacy and the default exports for the library were replaced with what was formerly expo-file-system/next . The quickest way to upgrade and have your app working the same as before is to replace all imports for expo-file-system to expo-file-system/legacy. Next, you can migrate to the new API at your own pace. If you were already using expo-file-system/next, update your imports to expo-file-system instead. Learn more about the new API.
  • expo-notifications deprecated function exports were removed expo/expo#38782.

Tool version bumps

  • Minimum Xcode bumped to 16.1.
  • Minimum Node version bumped to 20.19.x.

Known issues

  • Hotkeys for reloading and opening the dev menu in iOS 18.4+ simulators not reliably firing. We are investigating the issue. In the meantime, you can use the interactive prompt in Expo CLI to perform both actions and more.
  • Expo CLI’s Live Bindings implementation usually prevents require cycles from failing. However, if the entire cycle only consists of default-imports, this will still fail. We are working on a fix for this.
  • In React Native 0.81.0, apps that are compiled in Release using the precompiled XCFrameworks can’t be submitted to the store: this will be resolved in 0.81.1, which will be available during the week of August 25. In the meantime, if you’d like to submit a build to TestFlight you can disable this behavior with expo-build-properties by setting ios.buildReactNativeFromSource to false.
  • macOS 26 / Xcode 26 / React Native 0.81.0 / precompiled React Native: this particular combination of tools/configuration will lead to an error during the pod install phase. Learn more and how to work around this issue until 0.81.1 is released.
  • Expo CLI and Expo Tools for VSCode will warn when you provide iOS icons generated from the Icon Composer (.icon). This validation issue will be resolved shortly, and should not interfere with usage.

Known regressions

How to try out the beta release

Initialize a new project with SDK 54 beta

Terminal
# npm
npx create-expo-app@latest --template default@next
# bun
bun create expo-app --template default@next
# pnpm
pnpm create expo-app --template default@next
# yarn
yarn create expo-app --template default@next

Note: create-expo-app will install dependencies with the package manager that you are using. For example, with npm when npx is used and yarn when yarn create used.

Upgrade an existing project

  • Upgrade all dependencies to match SDK 54:
Terminal
npx expo install expo@next --fix
  • Install the latest Expo Go for Android emulators/physical devices or iOS simulators:
    • Launch your project through Expo CLI (press the a or i keyboard shortcut after running npx expo start) and the updated version of Expo Go will be automatically installed.
  • Install the latest Expo Go for iOS to your physical device: Join the TestFlight External Beta.
  • Read the documentation by selecting it from the version selector in the API reference section.

What to test

  • Upgrade your app with npm install expo@next or yarn add expo@next, then run npx expo install --fix and consult the Native project upgrade helper and report any issues you encounter.
  • Build your app with EAS Build, and/or if you have Xcode installed and up to date on your machine and/or Android Studio, try prebuilding your app and running it: npx expo prebuild --clean and npm run ios and npm run android. Alternatively, try out npx expo run. Any new issues? Please report them.
  • Did we miss updating the documentation somewhere? Let us know.

How to report issues

Thank you for helping us with testing the release — we look forward to shipping it soon! 🚀