Skip to main content
React Native 0.87: Strict TypeScript, AGP 9, and SwiftPM upgrade guide

React Native 0.87: Strict TypeScript, AGP 9, and SwiftPM upgrade guide

React Native 0.87 was released on 11 August 2026. It brings meaningful improvements to Metro, TypeScript, and iOS setup, but also raises tool requirements and removes old APIs. An upgrade is more than changing a version in package.json, especially for an Arabic app, a native-heavy dependency graph, or an older CI image.

The Strict TypeScript API is now the default, Metro moves to 0.87, and experimental Swift Package Manager support arrives. Android requirements rise to Node.js 22.13 or newer, Kotlin 2.0 or newer, AGP 9, and compile SDK 37 in the reference setup.

Official React Native 0.87 announcement

Why the Strict TypeScript API matters

React Native’s previous types were maintained separately and could drift from source. The strict types are generated from the code and define the public API around root exports. That improves accuracy, but it exposes application or library dependencies on internal paths such as:

import SomeInternalThing from "react-native/Libraries/...";

In 0.87, deep imports become type errors and several type names or shapes change. Replacing every error with any defeats the purpose. Search the application and dependencies for internal imports, move to a public export or maintained package, and verify runtime behavior on a device.

There is a temporary react-native-legacy-deep-imports opt-out. The release notes say it remains through 0.88 and that legacy types are intended for removal in the following release. Treat the switch as a dated bridge with an owner, not a permanent fix.

Android requirements may break CI first

The build may fail before JavaScript runs because the environment changed:

  • Node.js 22.13 or newer.
  • Kotlin 2.0 or newer, with 2.2 bundled.
  • Android Gradle Plugin 9.
  • Library minCompileSdk 34 and project compile SDK 37.
  • Related Gradle, Java, and plugin compatibility changes.

Pin Node, JDK, and Android SDK versions in CI instead of relying on latest. Inspect every native dependency. A compatible application is not enough when an old package uses a removed API or incompatible Gradle configuration.

Metro improves while old configuration disappears

Meta reports faster source-map generation, lower source-map memory use, and stable TypeScript and ESM configuration support. Metro no longer supports YAML configuration or JavaScript config files with the .es6 extension.

Measure cold build, incremental build, and DevTools startup on the same machine. Do not credit Metro for every difference when Node, Gradle, and caches also changed. Keep the timing and logs if CI duration has a direct team cost.

SwiftPM is experimental, not an automatic production decision

React Native 0.87 introduces an experimental path to Swift Package Manager as an alternative to CocoaPods. Removing Ruby and repeated pod install steps is attractive, but the release explicitly keeps CocoaPods as the default supported path.

Do not migrate a published application only because the feature is new. Some libraries lack Package.swift, commands and generated structure may change, and CI needs an initialization step. Test SwiftPM on a separate branch or internal app. Inventory every native library, extension, build phase, signing setting, and capability before comparing paths.

Removed and changed APIs

The release removes InteractionManager in favor of requestIdleCallback, old Modal and StatusBar properties, some ScrollView behavior, and tooling packages. useColorScheme changes its return shape, Jest preset packaging changed, and new deprecations include ImageBackground and Android APIs.

Search for every symbol called out in the release notes across your code and dependencies. Resolve each use with a test rather than running a broad codemod and accepting a large diff without review.

A controlled upgrade path

  1. Record baseline iOS and Android builds, tests, bundle size, startup, and crashes.
  2. Upgrade the toolchain in CI and one reproducible local environment.
  3. Use Upgrade Helper and review template changes manually.
  4. Enable Strict API and resolve deep imports before considering the opt-out.
  5. Upgrade native libraries in small groups.
  6. Run unit, integration, and E2E tests, then signed release builds.
  7. Prefer connected physical iPhone and Android devices when available.
  8. Ship to a test channel before store production.

Do not shorten the RTL matrix

An English pass is not evidence that an Arabic application is ready. Test:

  • cold start in Arabic, then English, and the reverse;
  • mixed text such as QAR 1,250, an order ID, and email;
  • back arrows, gestures, drawers, and bottom sheets;
  • useColorScheme() because it can now return null;
  • large text, VoiceOver, and TalkBack;
  • notification, deep link, and permission screens;
  • a signed release build rather than Metro development alone.

Compare screenshots before and after in both directions. TypeScript can pass while an icon mirrors incorrectly, a safe area changes, or a navigation dependency fails only on Android.

Business impact

The benefit is a clearer API, current tooling, improved Metro, and a possible simpler future iOS setup. The cost is compatibility work across libraries, CI, and devices. A project that relies heavily on internals will pay more now, but it was already carrying hidden risk.

Do not let a store release deadline be the first encounter with AGP 9 or Strict API. Keep the upgrade separate from a large feature so failures are attributable and rollback remains simple.

My recommendation

I would start a dedicated upgrade branch now for an app on a nearby supported version, but I would not promise a one-day migration. Fix deep imports instead of hiding them, pin the toolchain, and keep CocoaPods in production until SwiftPM proves compatible with every dependency. For an Arabic app, the upgrade is incomplete without signed builds and real RTL testing.

Sources and review date