Expo SDK 56 Beta is now available

Alan HughesAlan Hughes
Brent VatneBrent Vatne
Expo SDK 56 beta is now available. SDK 56 beta includes React Native 0.85

The SDK 56 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 56 beta includes React Native 0.85.2 and React 19.2.3. The full release notes for SDK 56 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.

Expo Go for SDK 56 on iOS simulators, eas go, and Android simulators and devices will be available later this week or early next week. For an update on the current status of Expo Go on the App Store, refer to "Expo Go and the App Store in May 2026".

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

Expo UI is now ready for production

As of SDK 56, the Jetpack Compose (Android) and SwiftUI (iOS) APIs in Expo UI are stable. We've added Expo UI to the default create-expo-app template, so new Expo apps can use a rich set of native UI primitives right out of the box, and Expo UI is now available in Expo Go.

This milestone release builds on three SDK cycles of iteration across SDK 53, 54, and 55. Thank you to everyone on the Expo team and in the community who helped test, audit, and refine the APIs from the original SwiftUI prototype to the Jetpack Compose implementation.

SDK 56 focuses on three core pieces of Expo UI: a new universal components API for shared interfaces, stable native APIs, and drop-in replacements for popular React Native community libraries.

Universal components

Expo UI now includes universal components that work across Android, iOS, and web. Unlike the Android and iOS APIs, the web APIs are still experimental and likely to change.

The universal components are backed by @expo/ui/jetpack-compose on Android, @expo/ui/swift-ui on iOS, and react-dom or react-native-web on web. You can now build more cross-platform UI with Expo UI without splitting files into .android.tsx and .ios.tsx.

Universal components include layout primitives, text, inputs, controls, and sheets such as Host, Row, Column, ScrollView, Text, TextInput, Button, Switch, Slider, Checkbox, and BottomSheet. Learn more.

Stable native APIs

Expo UI's SwiftUI and Jetpack Compose APIs are now stable after several rounds of breaking changes. These changes align Expo UI more closely with the underlying frameworks, so developers and coding agents can lean on native platform documentation and examples directly when writing Expo UI code.

  • Extend Expo UI with custom views and modifiers: you can now extend Expo UI with your own SwiftUI and Jetpack Compose views and modifiers. Expo UI manages layout synchronization, props, and events for you. See the guides for examples: SwiftUI guide and Compose guide.
  • react-native-worklets integration and native state: Expo UI now integrates with react-native-worklets and native state primitives from the underlying UI frameworks: ObservableObject on SwiftUI and MutableState on Jetpack Compose. The new useNativeState hook lets JavaScript control that native state directly, which is useful for native state-driven animations and form controls. Learn more about useNativeState for SwiftUI and Jetpack Compose.
  • Synchronous worklet callbacks: a new WorkletCallback shared object allows synchronous UI worklet callbacks to be passed as props to Expo UI views on both platforms. TextField on iOS and Compose can now use native state for value, and onValueChange accepts WorkletCallback, enabling synchronous, flicker-free controlled text inputs.
  • Components, modifiers, and API changes: SDK 56 lands the bulk of the stabilization work since SDK 55. See the @expo/ui CHANGELOG for the full list.

Drop-in replacements for community components

Expo UI is focused on native primitives, and some of those primitives overlap with popular community libraries. To make migration easier and reduce library fragmentation, SDK 56 introduces drop-in replacements for several common community components.

For example, you can migrate from:

to:

Drop-in replacements are available for @react-native-segmented-control/segmented-control, @react-native-picker/picker, @react-native-community/datetimepicker, and @gorhom/bottom-sheet APIs. Most migrations only require changing the import, though some props may differ because Expo UI is backed by SwiftUI and Jetpack Compose rather than UIKit and Android Views. Learn more.

Faster builds with precompiled Expo packages

SDK 56 ships prebuilt XCFrameworks for our most complex Expo modules on iOS, to speed up your iOS builds. This is enabled by default both locally and on EAS Build — no configuration required. To opt out, set the EXPO_USE_PRECOMPILED_MODULES environment variable to 0 (for local builds), and also as an EAS environment variable (for EAS Build).

Expo Modules: easier to write, faster to run

Inline modules

Starting with SDK 56, you can now define Expo modules directly within your project structure, alongside your JavaScript and TypeScript code. We call these inline modules, and they make experimenting with native code easier than ever.

After setting up your app to use inline modules, you can open Kotlin and Swift files and write your Expo modules with no additional setup. During prebuild, the iOS Xcode project is updated and the necessary options are set in the Android project, which lets us add inline modules to the build and autolink them automatically.

With the newly released type generation tools, which offer a few CLI commands tailored towards inline modules, you will have an even smoother experience. You can just create a Swift inline module and a CLI watcher will automatically generate a TypeScript interface for it right beside the Swift file. The TypeScript interface is separated into a generated and stable part, so that you have control over your stable TS interface and leave the generated part to be regenerated on any changes. If you want more control you can always generate these files manually.

You can develop inline modules from Android Studio, Xcode, or any other IDE as they are part of your project structure.

Check out the inline modules reference and the tutorial for more information!

Revamped create-expo-module

In SDK 56, create-expo-module has been revamped for improved stability and a richer feature-set.

  • New create-expo-module skill: helps agents create Expo modules — coming soon.
  • New addPlatformSupport subcommand: adds support for additional platforms in an existing module — for example, adding Android support to an iOS-only module. The command detects the features currently used in your module and scaffolds the native files for you.
  • Modular template: when creating a module you can pick which features get scaffolded and which platforms it targets.
  • Non-interactive mode support: field defaults have been improved and some fields are no longer required; in non-interactive mode, create-expo-module logs the defaults that were used.
  • No barrel file by default: local modules no longer use index.ts; pass --barrel to opt in.
  • Windows support: create-expo-module now works well on Windows.

Runtime performance improvements in expo-modules-core

Kotlin compiler plugin — A new Kotlin compiler plugin replaces reflection with build-time code generation for Expo Modules on Android. In our benchmarks, we're seeing roughly 40% faster cold starts and 33% faster first render, with no app-side changes required. By collecting module metadata at compile time rather than runtime, we eliminate the reflection-based function-type-to-converter mapping that has historically been a major speed bump for Expo Modules on Android. Results will vary by project, but this is only the beginning — this compiler-driven approach lets us optimize function invocation directly, starting with a noticeable speed boost for Record conversion in SDK 56.

New JSI layer for iOS native modules — Until now, calling into a native module from JavaScript on iOS meant crossing three language boundaries: Swift, Objective-C++, and C++. In SDK 56 we removed the Objective-C++ middle layer entirely by adopting Swift/C++ interop to talk to JSI directly. Fewer hops means less call overhead, and in our benchmarks we're seeing significant performance improvements across native module calls. The codebase is also significantly easier to work with now that it is Swift all the way down. We'll cover the architecture, benchmarks, and what this enables in an in-depth blog post.

React Native 0.85.2 and React 19.2.3

Expo SDK 55 included React Native 0.83, so be sure to refer to the full release notes for 0.84 and 0.85 for the complete picture. A few highlights include:

  • Hermes V1 by default: Hermes V1 is now the default JavaScript engine, bringing faster startup times, improved runtime performance, and reduced memory usage. You can opt out with the useHermesV1 configuration in expo-build-properties.
  • New Animation Backend: React Native 0.85 introduces a new animation backend designed to better align with the New Architecture, improving consistency and performance of animations across platforms.
  • The Metro dev server now supports HTTPS via TLS configuration, enabling secure local development environments and compatibility with APIs that require secure origins.
  • React Native 0.85 drops support for end-of-life (EOL) Node.js versions and releases before v20.19.4.

More capable expo-file-system

SDK 56 fills several parity gaps in the new expo-file-system API that became the default in SDK 54. File.downloadFileAsync() now reports progress and supports AbortSignal, and copy/move operations accept an overwrite option.

The new API also adds task-based upload and download APIs: file.createUploadTask() and File.createDownloadTask(). These bring back support for long-running transfers from the legacy file-system module, including upload progress, cancellation, and resumable downloads. For simpler uploads, File.upload() provides a convenience wrapper when you do not need to manage an upload task directly.

File picking is more capable now too: File.pickFileAsync() supports selecting multiple files and multiple MIME types, bringing it closer to expo-document-picker feature parity. We also fixed several correctness and reliability issues, including large-file md5 hashing memory usage, Android SAF copy/move support, and totalDiskSpace reporting on iOS.

We've also added experimental file-system event watching with File.watch() and Directory.watch(), which will let apps subscribe to file and directory changes without polling.

Status bar and navigation bar APIs are now consistent

Both expo-status-bar and expo-navigation-bar now expose a React component with the same prop surface, where multiple instances merge in mount order. To make that possible, we added a new <NavigationBar> component:

We also added a config plugin for expo-status-bar, and both packages' plugin options now align:

New Calendar, Contacts, and MediaLibrary APIs are now stable

With the release of Expo SDK 56, the next versions of the expo-calendar, expo-media-library, and expo-contacts libraries are officially promoted to stable.

The updated APIs have been redesigned with an object-oriented approach. Items like media assets or individual contacts are now represented as classes, which unlocks new features and makes them much easier to work with. Key improvements include granular data fetching (instead of loading entire, heavy objects at once, you can now fetch the specific properties you need) and cleaner querying and filtering using the Builder pattern.

For more technical details and usage examples on the new MediaLibrary and Contacts APIs, check out the blog post.

Widgets for iOS promoted to stable

After introducing an alpha version of Expo Widgets for iOS in SDK 55, we gathered feedback and made many fixes and improvements, and the library is now stable. In SDK 56, Widgets and Live Activities have full access to the React context and no longer need to be pre-rendered. We also improved timeline management, error handling, the config plugin, and the render timeline.

AI-friendly project scaffolding

  • Agent-ready scaffolding: new projects include AGENTS.md, CLAUDE.md, and .claude/settings.json with Expo-specific guidance.
  • Official Expo Skills for AI agents: install in Claude Code with /plugin marketplace add expo/skills followed by /plugin install expo. For Codex, Cursor, or any other agent, run npx skills add expo/skills. See the skills docs for per-tool setup details.

Expo CLI

SDK 56 ships the first wave of performance improvements across the whole bundling and run pipeline, with more landing in future releases.

  • Faster bundler warmup: the time from expo start to a running bundling server is reduced — especially for monorepos with isolated dependencies, where we're seeing up to a 30% reduction in load time in the most extreme cases.
  • watchFolders-free Metro experiment: eliminates watchFolders as a load-bearing configuration option, which also enables support for package manager global stores (such as in pnpm and bun) — useful in combination with Git worktrees. Enabled by default; disable it by adding experiment.onDemandFilesystem: false to your app.json.
  • Native Node.js watcher by default: rather than Watchman, we now use a native Node.js watcher and crawler by default. You can switch back to Watchman with resolver.useWatchman in a Metro config, but it's no longer recommended.
  • TypeScript 6 support and TypeScript 7 readiness: we replaced our TypeScript resolution to support TS 6 and prepare for TS 7. This resolves some monorepo bugs with tsconfig.json's paths config.
  • Faster resolution: Module resolution has been sped up and the TypeScript resolution now has a lower impact on resolution times.
  • import.meta support: import.meta support is now automatically enabled.
  • Hermes v1 transforms: fewer bundler transforms are enabled for Hermes, which reduces bundling times overall.

Expo Router

As of SDK 56, expo-router no longer sits on top of react-navigation — we've rebuilt it on a new foundation. As a result, most code imported directly from @react-navigation/* packages will no longer work out of the box.

Run the codemod to handle most of the migration automatically (replace [your-source-directory] with your source folder, e.g. src or app):

See the migration guide for full details, including manual migration steps.

On Android, we've added experimental support for a toolbar. You can try it using the same API available on iOS: Stack.Toolbar.

In collaboration with react-native-screens, we've also introduced experimental support for a new version of the native stack (Stack v5), including initial support for Material-style headers and predictive back gesture.

We've also added the ability to customize the default <Suspense> fallbacks in a _layout route, giving you more control over loading states across your app. Following the same convention as ErrorBoundary, you can export a SuspenseFallback that receives route parameters, making it easy to show loading UI:

For Expo on the Web, we now support streaming SSR when using the unstable_useServerRendering flag. As part of this change, we've also introduced a new generateMetadata function for retrieving and setting metadata on initial page load. The existing <Head> component can still be used for updating metadata after hydration. Check out the updated documentation and let us know how it works for you!

We've also added two new helpers for data loaders: createStaticLoader and createServerLoader, which narrow the callback signature for each rendering mode. createStaticLoader receives only route params (no request), while createServerLoader always passes a request and throws an actionable error if mistakenly used during static generation.

Brownfield: more flexibility for embedded Expo apps

SDK 56 builds on the brownfield foundation we shipped in SDK 55, with three meaningful additions for teams embedding Expo into existing native apps.

Multiple isolated apps in one host. A new experimental option lets one host app contain multiple inner expo-brownfield apps. Opt in by setting multipleFrameworks: true on the iOS plugin config, and each framework gets a unique Swift module name plus an auto-applied ObjC symbol prefix across its entire pod dependency graph, so two brownfield apps can ship side by side without colliding.

Custom Turbo Modules from the host app. Host apps can now register their own turbo module classes with the inner Expo app's React Native runtime, by passing a turboModuleClasses dictionary into ReactNativeHostManager.initialize. This makes it much easier to expose host-app capabilities (auth, app-specific SDKs, native UI controllers) to JavaScript without modifying the inner app's bundle.

iOS prebuilds by default. expo-brownfield now uses prebuilt React Native frameworks on iOS out of the box, which substantially cuts brownfield build times. If you need to opt back into building React Native from source, use the new buildReactNativeFromSource plugin option.

Other notable changes

  • expo-audio: new useAudioStream hook for real-time microphone buffer access (#44902). Live-stream improvements: isLiveStream lock-screen option on iOS (#43088), playsInSilentMode on Android (#43117), and isLive / currentOffsetFromLive / error fields on AudioStatus (#44441).
  • expo-haptics: web haptics on Safari (#44261).
  • expo-asset: GLB model assets for 3D / AR work (#42495).
  • expo-sqlite: native ArrayBuffer for blob columns (Android #42640 / iOS #42642), statement bind params (#42639), and session changesets (#42638) — replacing the legacy JavaScriptArrayBuffer.
  • expo-dev-launcher: error-screen "Copy" button (#44723), NDS service discovery on Android, Android edge-to-edge (#44529), and plugin options for defaultLaunchURL (#44419), skipOnboarding, and showMenuAtLaunch (#45167).
  • expo-doctor: a new check warns when expo-router and react-navigation are both installed — a likely unintended pairing now that expo-router no longer sits on top of react-navigation (#45323).

Tool version bumps

  • Minimum Xcode bumped to 26.4.
  • Minimum iOS / tvOS bumped to 16.4, macOS to 13.4. Up from iOS 15.1 (last bumped August 2024). Drops support for iPhone 7/7+, iPhone 6s/6s+, iPhone SE (1st gen), iPad mini 4, and iPad Air 2.
  • TypeScript bumped to 6.0.3 — included in new project templates and pulled in for existing projects via npx expo install --fix. To opt out, add typescript to the expo.install.exclude field in your package.json.

Deprecations

  • @expo/vector-icons will be replaced by @react-native-vector-icons/*: the new scoped packages (one per icon set, e.g. @react-native-vector-icons/material-design-icons) are distinct from the older umbrella react-native-vector-icons package that @expo/vector-icons originally replaced. @expo/vector-icons was created for Expo Go compatibility; recent upstream work has made that wrapper unnecessary, so consolidating onto @react-native-vector-icons/* reduces duplication and gives you the latest icons and fixes directly. Migrate today by running npx @react-native-vector-icons/codemodlearn more about the codemod.
  • Original expo-calendar, expo-contacts, and expo-media-library APIs: superseded by the redesigned versions now promoted to stable — the original APIs are deprecated.

Notable breaking changes

  • expo/fetch as globalThis.fetch: expo/fetch is now installed as the default implementation of globalThis.fetch, providing a WinterTC-compliant API and improved performance. Manual imports are no longer required. To opt out, set EXPO_PUBLIC_USE_RN_FETCH=1 in your .env file. Learn more.
  • Async copy() and move() in expo-file-system: these methods on File and Directory are now asynchronous and return a Promise. Use copySync() and moveSync() for synchronous behavior.
  • @expo/dom-webview as the default WebView for DOM components: you no longer need the react-native-webview dependency to use DOM components. You can still opt out and continue using react-native-webview if needed. Learn more in the usage guide.

How to try out the beta release

Initialize a new project with SDK 56 beta

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 is used.

Upgrade an existing project

Try using our expo/skills upgrade skills with Claude Code to upgrade your app to the beta. We appreciate reports for any issues that you encounter so we can further tune it in the coming weeks.

The following instructions explain the manual steps to upgrade your app.

  • Upgrade all dependencies to match SDK 56:
  • Read the SDK 56 documentation for full API references.
  • iOS deployment target bump: if you have any Expo modules of your own, update the iOS deployment target to 16.4 in your podspec.

What to test

How to report issues