Summary:
Replaces https://github.com/react/react-native/issues/57352.
Self-register commands from the `community-cli-plugin` package via `react-native.config.js` — meaning we can remove the redirect within `packages/react-native/react-native.config.js`.
Progress towards removing `community-cli-plugin` as a direct dep of `react-native`, and paired with https://github.com/react-native-community/template/pull/235.
RNTester and HelloWorld list `react-native/community-cli-plugin` in `devDependencies`, as the template now does (react-native-community/template#235).
Changelog:
[General][Breaking] - `react-native/community-cli-plugin` will no longer be auto-detected from `react-native`. It must now be specified in `devDependencies`.
Pull Request resolved: https://github.com/react/react-native/pull/58670
Test Plan:
Compared `react-native config` output with `react-native-community/cli` 20.2.0.
**RNTester**
- ✅ Commands, platforms, and project config are unchanged from `main`
- ✅ Removing the new `react-native/community-cli-plugin` devDependency drops `bundle`, `start`, `spm`, and `codegen`, so they are registered by plugin discovery
**Template-shaped app** (plugin in `devDependencies`, no project `react-native.config.js`)
- ✅ `bundle`, `start`, `spm`, and `codegen` are registered
Reviewed By: christophpurrer, cortinico
Differential Revision: D121634885
Pulled By: Abbondanzo
fbshipit-source-id: e97c9f820d3c597233ef4a7ddaaf1b752f1f7688
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58469
TurboModules, Fabric and bridgeless are all unconditionally enabled in the New
Architecture, so every remaining flag on `DefaultNewArchitectureEntryPoint` was
dead configuration. Reduce it to the one thing it still selects: the release
level.
Removes the deprecated parameterized `load(...)` overloads, the `fabricEnabled`,
`turboModulesEnabled` and `concurrentReactEnabled` getters, and
`isConfigurationValid`. Call sites that passed `fabricEnabled` to
`DefaultReactActivityDelegate` now use its two-argument constructor, which
already ignored the flag.
Changelog:
[Android][Breaking] - Remove the deprecated `DefaultNewArchitectureEntryPoint.load(turboModulesEnabled, fabricEnabled)` overloads; use `load()` instead
[Android][Breaking] - Remove `DefaultNewArchitectureEntryPoint.fabricEnabled`, `turboModulesEnabled`, `concurrentReactEnabled` and `isConfigurationValid`
Reviewed By: javache
Differential Revision: D119370657
fbshipit-source-id: 4964d5163af9bc1a74e3a4b9ae6933df98683e5f
Summary:
Use an asset catalog for images on iOS. At build time, `react-native-xcode.sh` has the bundler emit packager image assets into a staging asset catalog (`--asset-catalog-dest`, already in `react-native/community-cli-plugin`), compiles it with `actool` into an `RNAssets.bundle` inside the app, and the native image loader resolves images by name from that bundle's `Assets.car` with `[UIImage imageNamed:inBundle:]` instead of reading loose files.
Properties worth calling out:
- **One opt-in switch, no project changes.** The feature is gated on the `RCTUseAssetCatalog` key in the app's Info.plist, and that key is the single source of truth: the native loader reads it (a build-time constant, read once), and `react-native-xcode.sh` reads the same key to decide whether to bundle images into the catalog — so the build and the runtime cannot disagree on where image assets live. Because the script owns the catalog end to end (staged in derived files, compiled into the app's resources next to `main.jsbundle`), **migration is adding one Info.plist key** — no `.xcassets` to create, no build-phase or project changes.
- **No fallback.** The catalog path is a single lookup with no filesystem fallback — a mis-bundled asset logs an `RCTLogError` (instead of silently rendering nothing) rather than adding an `fs` stat to the hot path.
- **Parity with the CLI, OTA-safe.** The native side resolves a catalog name only for what the CLI actually emits into the catalog: png/jpg/jpeg under main-bundle `assets/…` (mirroring `isCatalogAsset`). Everything else — gif/webp packager assets, `.bundle` sub-bundles, OTA assets outside the main bundle — falls through to the existing loader. (This also adds `jpeg` to `RCTIsImageAssetsPath`, which previously listed only `png`/`jpg` — an oversight, since `.jpeg` is the same kind of bundled image; it is now treated like `png`/`jpg` regardless of the catalog.)
- **No interference with Xcode's own asset pipeline.** The app's `Images.xcassets`, asset symbol generation (`UIImage(resource:)`), and `CompileAssetCatalog` are untouched: the RN catalog never enters the Xcode project, so there are no build-phase ordering constraints and nothing to disable.
## Changelog:
[iOS] [Added] - Use asset catalog for ios images
## Performance
**What was measured:** the time to *resolve* an asset to a `UIImage` inside `RCTImageFromLocalAssetURL` — a compiled-catalog name lookup vs. the legacy `imageNamed:` search + `imageWithContentsOfFile:` on loose files. Decode is deferred in both paths (and costs the same), so this is resolve latency, not end-to-end render time. It matters because `RCTLocalAssetImageLoader` loads local assets synchronously to avoid flicker, so this time sits on the critical path once per distinct image. Setup: RNTester, Release, new arch, iOS simulator, first load of each distinct image (UIKit caches repeats — repeat loads are ~10 µs in both builds).
Raw per-load numbers (final implementation, `RNAssets.bundle`), in load order:
| # | image | catalog (µs) | filesystem (µs) |
|---|---|---:|---:|
| 1 | `searchicon` ¹ | 1,081 | 4,497 |
| 2 | `bottomnavcomponentsicondark` | 320 | 710 |
| 3 | `bottomnavplaygroundsiconlight` | 147 | 422 |
| 4 | `bottomnavapisiconlight` | 29 | 352 |
| 5 | `bottomnavcomponentsiconlight` | 320 | 1,410 |
| 6 | `uie_thumb_normal` | 67 | 667 |
| 7 | `uie_thumb_selected` | 32 | 468 |
| 8 | `uie_comment_normal` | 26 | 454 |
| 9 | `uie_comment_highlighted` | 31 | 671 |
| 10 | `verylargeimage` ² | 30 | 1,855 |
| 11 | `alphahotdog` | 171 | 592 |
¹ First load in each build pays one-time costs: mapping `Assets.car` on the catalog side, ImageIO/framework warm-up + first disk touch on the filesystem side.
² Resolve only — the large image's decode cost is unchanged, so its end-to-end win is much smaller than this row suggests.
Every image is faster from the catalog: median 67 µs vs 667 µs (**10×**; an earlier run of the same benchmark measured 47 µs vs 719 µs, ~15× — run-to-run variance, same order either way). The mechanism: the catalog is a single memory-mapped, indexed archive (one name lookup, no per-image syscalls), while the loose-file path does an `imageNamed:` search over several filename permutations plus a per-image file open.
The URL→catalog-name derivation on the native side is a single character pass with no regex; benchmarked against a straightforward regex-based implementation of the same transform it measures 4.9 µs vs 11.0 µs per call (2.2×, Debug build, including the shared URL→bundle-path resolution both share), so the name mapping is a negligible part of the lookup.
**App thinning:** verified that App Store slicing thins the `Assets.car` inside `RNAssets.bundle` exactly like the app's own catalog. Test: a fixture app with a 1x/2x/3x imageset in both its main `Images.xcassets` and an actool-compiled `RNAssets.bundle`, archived and exported with `thinning` for a 3x device — both cars were sliced to 3x-only. So unused scales are stripped per device (unlike today's loose packager files, which ship every scale to every device).
## Migration
To opt an app in, add to its `Info.plist`:
```xml
<key>RCTUseAssetCatalog</key>
<true/>
```
That's the entire migration — no `.xcassets` to create, no build-phase or project changes. Notes:
- **Do a clean build after changing the key.** Incremental builds don't remove image assets a previous build placed with the other setting (unused, but dead weight in local builds; archives are unaffected).
- The key must be a literal value in the app's source Info.plist: the build script reads it with PlistBuddy (accepting the same value forms the runtime `boolValue` check accepts), so build-setting substitution or fully generated Info.plists (`GENERATE_INFOPLIST_FILE`) aren't seen by the script and stay on the legacy path. If bundling happens outside `react-native-xcode.sh` (custom CI calling `react-native bundle` directly) while the key is enabled, the native side detects the missing `RNAssets.bundle` and logs an actionable error instead of silently rendering nothing.
- Incomplete but valid scale sets degrade gracefully: an imageset with, say, only a `2x` (no `3x`) is kept for a 3x device by App Store slicing and used at runtime — verified with a thinned export. Only a *non-integer*-only asset (e.g. an Android-density `1.5x` with no `1x`/`2x`/`3x` variant, which iOS asset catalogs cannot represent) is unsupported: `actool` drops it with an `Unknown scale value` warning in the build log and the runtime logs an error. That's a rare antipattern; a `community-cli-plugin` follow-up will turn it into a clear build-time error at the source (it has the scale and asset path), rather than this repo re-parsing actool output.
- OTA updates keep working: assets delivered outside the main bundle never resolve to the catalog and use the regular loader.
- Docs follow-up: a section on the website's Images page (`react-native-website`) and the one-line opt-in in `react-native-community/template` will be separate PRs, timed with the release that ships this.
Pull Request resolved: https://github.com/react/react-native/pull/30129
Test Plan:
RNTester and `private/helloworld` both opt in (`RCTUseAssetCatalog=YES` in their Info.plists — the only change an app needs), so CI covers the catalog path on both app shapes. The new-project template lives in `react-native-community/template` and will get the same one-line opt-in in a follow-up PR there. To test locally with RNTester:
1. In Xcode, edit the RNTester scheme → set Build Configuration to Release.
2. Build & run. Local images render, served from `RNAssets.bundle/Assets.car`; the app contains no loose packager png/jpg files.
Unit coverage in `RCTURLUtilsTests` (`testAssetCatalogNameForURL`), asserting the identifiers the CLI generates: scale-suffix stripping (including non-integer `1.5x`), folder encoding, illegal-char removal, jpeg vs. non-catalog types (gif), out-of-project-root assets, query strings, non-packager paths, and nil.
Mac Catalyst: verified end-to-end by building rn-tester as a Mac Catalyst app — the catalog compiles (via the Catalyst-specific `--platform macosx --ui-framework-family uikit` actool invocation) into `RNTester.app/Contents/Resources/RNAssets.bundle` with all packager images and no loose files, and the runtime uses the same `imageNamed:inBundle:` mechanism CocoaPods resource bundles use on Catalyst. (rn-tester doesn't ship a Catalyst config, so this isn't in CI, but the build is clean.)
Reviewed By: cipolleschi
Differential Revision: D40095766
Pulled By: javache
fbshipit-source-id: 18dfcb47ae5185ef279b20dd0087de9a31e930b4
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57611
Directly follows D112733139 (Metro).
**Motivation**
- New Node builtins are *only* available under the prefix (e.g. `node:sqlite`), as this allows Node to introduce them without ecosystem-breaking changes, so this is the direction of travel and the only choice that'll allow consistency.
- Encouraging them and grouping them separately makes it easier to reason about a module's 3rd party dependencies.
Changelog: [Internal]
Reviewed By: robhogan
Differential Revision: D112803684
fbshipit-source-id: 40668d746a7151b3aa4800ff8af997902a18d198
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57355
Changelog: [INTERNAL] Fix Dependabot security update for concurrent-ruby in react-native
The Dependabot GitHub Action on `react/react-native` `main` has been failing repeatedly because of `concurrent-ruby`. A security advisory marks `concurrent-ruby < 1.3.7` as affected (patched in `1.3.7`), but all three RN Gemfiles pin `gem 'concurrent-ruby', '<= 1.3.4'`. Dependabot cannot satisfy the advisory under that pin, so it opens a security PR to bump to `1.3.7` and then, on every subsequent run, reports `pull_request_exists_for_latest_version` as a hard error — failing the check and regenerating the internal CI task.
The `<= 1.3.4` upper bound was originally added because `concurrent-ruby 1.3.5` dropped its `logger` dependency, which broke older `activesupport`/CocoaPods setups. That cause is already mitigated: every Gemfile now explicitly lists `gem 'logger'`. The upper-bound pin is therefore obsolete.
This change relaxes the constraint from `<= 1.3.4` to `>= 1.3.7` in all three Gemfiles (root, `private/helloworld`, `packages/rn-tester`) and updates the two corresponding `Gemfile.lock` files to resolve `concurrent-ruby 1.3.7`. `1.3.7` introduces no new transitive dependencies over `1.3.4`, so no other lockfile entries change. With the advisory satisfied on `main`, Dependabot stops recreating the security PR and the recurring check failure stops.
Reviewed By: javache
Differential Revision: D109967250
fbshipit-source-id: 88f702bc6677053456557591cfd703776bb6c018
Summary:
https://github.com/react/react-native/issues/57481 removed the `react-native/jest-preset.js` redirect module (and the `react-native/jest-preset` public export), but the in-repo `private/helloworld` app still referenced `preset: 'react-native'` in its Jest config. This breaks `yarn test` in the `test_ios_helloworld` CI job (which cascade-cancels the rest of the iOS matrix and turns the e2e retry `report` jobs red):
```
● Validation Error:
Module react-native should have "jest-preset.js" or "jest-preset.json" file at the root.
```
This migrates HelloWorld to the standalone `react-native/jest-preset` package — the documented migration path (see `packages/jest-preset/README.md`).
## Changes
- `private/helloworld/jest.config.js`: `preset: 'react-native'` → `preset: 'react-native/jest-preset'`
- `private/helloworld/package.json`: add `react-native/jest-preset` devDependency (`0.87.0-main`, matching the sibling `react-native/*` packages)
## Changelog:
[Internal] [Fixed] - Fix HelloWorld Jest preset after `react-native/jest-preset` removal
Pull Request resolved: https://github.com/react/react-native/pull/57491
Test Plan:
- `cd private/helloworld && yarn test` resolves the preset and runs (previously failed with the validation error above).
- CI `test_ios_helloworld` job.
Reviewed By: cortinico
Differential Revision: D111215532
Pulled By: cipolleschi
fbshipit-source-id: 2d60de619060e384b4a5b662a6f588ea3e368433
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57369
**Problem**
The separate `react-native/assets-registry` package includes a longstanding ecosystem footgun.
`registry.js` holds asset state in a module-scoped variable, which makes the package a stateful singleton: exactly one instance must exist per JS runtime, or registration and lookup diverge.
We provide no guarantee that this singleton requirement holds:
- The install layout — how the package manager dedupes packages in `node_modules` — decides how many copies exist, and `react-native`'s exact-version pin means third-party ranges never dedupe against it.
Effects:
- **Consumers silently break**: `expo-asset` and `expo-image` can land on a second copy: assets register in one, resolve as `undefined` from the other. Expo neutralizes this with a shim in `expo/cli` that redirects every registry import to a single virtual module — bare React Native + Metro has no such protection.
- **This blocks 1.0**: The ecosystem can't move from exact-version lockstep to semver ranges until stateful packages like the asset registry are safe to duplicate. Today, relaxing the pin would turn a latent footgun into a common one.
**To solve this**, move towards (but not quite yet) deleting `react-native/assets-registry`, in favour of a replacement `AssetRegistry` API offered directly by `react-native`.
**Key changes**
NOTE: **Reviewer note**: Browsing file changes on GitHub may be more focused — https://github.com/react/react-native/pull/57369/changes
NOTE: Squash of https://github.com/react/react-native/pull/57233 (D108750302) and https://github.com/react/react-native/pull/57232 (D108750303)
`'react-native'`:
- Add new `AssetRegistry` API, along with the `PackagerAsset` and `AssetDestPathResolver` root type exports in `react-native`.
- Add a new `'react-native/asset-registry'` secondary entry point — intended for Metro's `transformer.assetRegistryPath` config contract.
`react-native/assets-registry`:
- Update to source from this relocated implementation — fixing the duplicate install layout bug (where apps/frameworks enforce a single copy of `react-native`).
**Impact**
- **✅ Fixed**: Imports from either `react-native` or `react-native/assets-registry` in RN 0.87+ will be durable to duplicate package installs — Expo can remove their virtual module shim.
- **✅ Fixed**: Deep import `'react-native/Libraries/Image/AssetRegistry'` dependency removed (migrated in `react-native/metro-config`).
Changelog:
- [General][Fixed] - **assets-registry**: `react-native/assets-registry` now shares state across duplicate installs, sourcing from a relocated implementation in the `react-native` package
- [General][Added] - Add `AssetRegistry` API (replaces `react-native/assets-registry/registry`)
- [General][Breaking] - `react-native/Libraries/Image/AssetRegistry` is removed. Please use the `AssetRegistry` API (apps/library code) and/or the `react-native/asset-registry` entrypoint (Metro/build configs).
Reviewed By: robhogan
Differential Revision: D109019622
fbshipit-source-id: 75599a94a9aba084a1266f2128c448379d1596cd
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57368
**Context**
This stack intends to relocate the `AssetRegistry` API from `react-native/assets-registry` into `react-native` — addressing runtime safety and public deep imports issues (1.0 and JS Stable API blockers).
**This diff**
Create a new `react-native/asset-utils` package, intended for internal/framework use (read: **will not be an end user concern**). This re-houses `react-native/assets-registry/path-support.js`.
Stacked with the next two diffs, this contributes to the 0.87 objective to delete `react-native/assets-registry` towards install-layout-safe behaviour and JS deep import removal.
- (Temporarily, this leaves two copies of `path-support.js` until I enact the package removal down the stack.)
This change also enables us to de-duplicate `assetPathUtils.js` inside `community-cli-plugin` and use one source of truth.
- Additionally, we have fbsource consumers of this util that cannot have a circular Buck dep on `react-native`, so the main package was not a suitable relocation point (secondarily to not adding an awkward new public API here).
**Changes**
- Add `react-native/asset-utils` (`packages/asset-utils/`): `src/AssetPathUtils.js` containing Android path helpers and tests.
- De-duplicate usages in `community-cli-plugin`: delete `src/commands/bundle/assetPathUtils.js`.
Changelog:
[General][Added] - Introduce `react-native/asset-utils` package (relocates Android path utils for libraries/frameworks)
Reviewed By: robhogan
Differential Revision: D110045272
fbshipit-source-id: 781e75c58ae9ce7f0fa860e66beca3b9990d26ea
Summary:
This PR is part of Android Gradle Plugin v9 adoption. With this PR, we adopt the AGP9 repository wide and address the deprecated APIs with the newer ones.
This is in combination with https://github.com/facebook/react-native/pull/57038
<details>
<summary>
<b>Changes to `configureBuildConfigFieldsForLibraries` and `configureNamespaceForLibraries`</b>
</summary>
<br/>
These helpers are called from `ReactPlugin.apply`, but they currently iterate over `rootProject.allprojects`. Since `com.facebook.react` is applied by multiple Android library projects, each application of the plugin repeats the same traversal and attempts to register `finalizeDsl` callbacks for every Android library project.
The first traversal can register the callbacks successfully. However, a later traversal can reach a project whose Android DSL finalization phase has already completed. Starting with AGP 9, AGP explicitly errors when `finalizeDsl` is called after that phase has passed, which causes the build failure. [see](https://issuetracker.google.com/issues/436595826)
To understand this, consider following modules:
```
:react-native-safe-area-context
:react-native-mmkv
:react-native-skia
```
The current code on main, would result in executing the following block 3 times:
```kt
fun configureBuildConfigFieldsForLibraries(appProject: Project) {
appProject.rootProject.allprojects { subproject ->
println("=== subproject ${subproject.name}")
subproject.pluginManager.withPlugin("com.android.library") {
subproject.extensions
.getByType(LibraryAndroidComponentsExtension::class.java)
.finalizeDsl { ext -> ext.buildFeatures.buildConfig = true }
}
}
}
```
The output would be:
```
> Configure project: react-native-safe-area-context
=== subproject RNProject
=== subproject app
=== subproject react-native-safe-area-context
=== subproject react-native-mmkv
=== subproject react-native-skia
> Configure project: react-native-mmkv
=== subproject RNProject
=== subproject app
=== subproject react-native-safe-area-context
=== subproject react-native-mmkv
=== subproject react-native-skia
> Configure project: react-native-skia
=== subproject RNProject
=== subproject app
=== subproject react-native-safe-area-context
=== subproject react-native-mmkv
=== subproject react-native-skia
```
Now with AGP9, the same code will throw this error:
```
> Configure project: react-native-safe-area-context
=== subproject RNProject
=== subproject app
=== subproject react-native-safe-area-context
=== subproject react-native-mmkv
=== subproject react-native-skia
> Configure project: react-native-mmkv
=== subproject RNProject
=== subproject app
=== subproject react-native-safe-area-context
=== subproject react-native-mmkv
* What went wrong:
A problem occurred evaluating project': react-native-mmkv'.
> Failed to apply plugin
'com. facebook. react'
> It is too late to call
finalizeDst
as the DSL finalization
blocks have already been executed. \n
In particular, you cannot call 'finalizeDsl' within the "beforeVariants' or "onVariants' blocks.
Instead, you must call finalizeDsl' directly within the
"androidComponents' block
```
**Solution:**
Since these helpers are only intended to configure Android library projects that apply the React plugin, we can configure the current project inside `pluginManager.withPlugin("com.android.library")` instead of repeatedly configuring all projects from every plugin application.
```kt
fun configureBuildConfigFieldsForLibraries(project: Project) {
project.extensions
.getByType(LibraryAndroidComponentsExtension::class.java)
.finalizeDsl { ext ->
ext.buildFeatures.buildConfig = true
}
}
```
```kt
fun configureNamespaceForLibraries(project: Project) {
project.extensions
.getByType(LibraryAndroidComponentsExtension::class.java)
.finalizeDsl { ext ->
if (ext.namespace == null) {
val manifestFile =
project.layout.projectDirectory.file("src/main/AndroidManifest.xml").asFile
manifestFile
.takeIf { it.exists() }
?.let { file ->
getPackageNameFromManifest(file)?.let { packageName ->
ext.namespace = packageName
}
}
}
}
}
```
One important note for `configureNamespaceForLibraries` is that the old `com.android.build.gradle.LibraryExtension` is deprecated in favor of `com.android.build.api.dsl.LibraryExtension` - which does not expose `manifestFile` from the `sourceSets`. So we have to define a path for it. For most libraries, this should be OK but for the ones which define custom path, this will fail.
Hence, I believe, if it's important to have this fallback, we take this tradeoff. Otherwise, since there has been 2 years passed for AGP8 adoption and the time when this fallback was added, we may safely remove this function as almost all libraries now define a `namespace` in `android { }` DSL.
With the above in place, we make one final change and that is to move these two functions inside the `withPlugin("com.android.library")` as these are only intended for libraries and that way, we also ensure that these will only be applied once the `com.android.library` plugin has been applied.
```kt
project.pluginManager.withPlugin("com.android.library") {
configureBuildConfigFieldsForLibraries(project)
configureNamespaceForLibraries(project)
configureCodegen(project, extension, rootExtension, isLibrary = true)
}
```
</details>
## Changelog:
<!-- Help reviewers and the release process by writing your own changelog entry.
Pick one each for the category and type tags:
[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message
For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->
[ANDROID] [BREAKING] - Adopt AGP v9
Pull Request resolved: https://github.com/facebook/react-native/pull/57038
Test Plan:
- CI passes
- Verified on RN Tester
- Verified on Local RN App
https://github.com/user-attachments/assets/b424c211-6876-42b0-a5d1-f9ecade39a3a
Reviewed By: cipolleschi
Differential Revision: D107656378
Pulled By: cortinico
fbshipit-source-id: 38fd7191e089ce29ccb84fa25bff6d9e920cf322
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/57034
With D107165685, it should work this time.
Changelog: [Internal]
Reviewed By: gkz
Differential Revision: D107111468
fbshipit-source-id: 326b2911088d7c87c3564a578125eeaab9d0b8cc
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56998
Reverts the recent Flow syntax codemods applied across `packages/`, `private/`, and `scripts/` in react-native-github. Specifically restores the previous form for:
- `+T` / `+Instance` style variance annotations on generic type parameters that had been converted to the newer `out T` / `in T` keyword form.
- `+field:` covariant object/interface properties that had been converted to the `readonly field:` modifier form.
- `+[K in keyof T]:` mapped-type covariance that had been converted to `readonly [K in keyof T]:`.
These are purely Flow type-annotation changes with no runtime behavior impact, restoring the form that the rest of the toolchain (in particular Fantom) already supports.
Changelog: [Internal]
Reviewed By: christophpurrer
Differential Revision: D106813102
fbshipit-source-id: 6bf915d530e130eba9c9d96a2b6c3dc8853594d1
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56922
Move `react-native/core-cli-utils` from `packages/` to `private/`, stop publishing it to npm, and reframe it as a reference implementation of React Native CLI tooling.
The package has no known external consumers and is only used internally by `private/helloworld/` and `packages/rn-tester/`. Publishing it to npm creates a maintenance surface for a package that serves no external users.
See https://github.com/react-native-community/discussions-and-proposals/pull/1002.
#### Changes
- Move `packages/core-cli-utils/` to `private/core-cli-utils/`.
- Convert all source files to CJS (require/module.exports) with Flow comment syntax (/*:: */), eliminating the runtime Babel dependency.
- Remove from the JS build pipeline (`scripts/build/config.js`).
- Remove the defunct `patchCoreCLIUtilsPackageJSON()` runtime patching from both `helloworld/cli.js` and `rn-tester/cli.js`, and delete both `monorepo.js` files that contained it.
- Add as `devDependency` to `rn-tester` and `helloworld`.
- Skip `"*"` version deps in `_prepareHelloWorld()` so they aren't rewritten to the Verdaccio-published version.
- Remove redundant desktop import ignore entry (`private/**` already covers it).
- Rewrite README as reference implementation documentation.
Changelog:
[General][Breaking] - The `react-native/core-cli-utils` package is no longer published. It remains available in the React Native repo as a reference implementation.
Reviewed By: cortinico
Differential Revision: D105959855
fbshipit-source-id: 42e439a45273bdeca76029eff306cdf2451308e2
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56925
(Tried this a while back, but now we have Claude to drive the fbsource references to resolution.)
No changes to the package name on npm or any APIs — consumers importing `react-native/assets-registry` are unaffected.
Changelog: [Internal]
Reviewed By: jdlehman
Differential Revision: D105990907
fbshipit-source-id: 9c9f3f6d4f43e39d093622df9a2d889e186e0b0e
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56891
(Tried this a while back, but now we have Claude to drive the fbsource references to resolution.)
No changes to the package name on npm or any APIs — consumers importing `react-native/assets-registry` are unaffected.
Changelog: [Internal]
Reviewed By: YeBrian
Differential Revision: D105686184
fbshipit-source-id: 700481d0937cb36490f5c3d8afc9924c0a804575
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56887
Drop support for Node.js 20. The minimum supported version is now `^22.13.0 || ^24.3.0 || >= 26.0.0`.
Node.js 20 reached end-of-life in April 2026 and is no longer actively maintained. This aligns React Native with the upcoming Metro requirement.
Changelog:
[General][Breaking] - Require Node.js >= 22.13.0
Reviewed By: christophpurrer, cortinico
Differential Revision: D105685641
fbshipit-source-id: f490e5a13e4289daba98c4d56dd8fdd341aef0db
Summary:
Ruby 3.4 removed 'kconv' (which requires 'nkf') and 'base64' from the standard library. This commit adds them to the Gemfiles to fix 'pod install' failures on Ruby 3.4 environments.
## Changelog:
[iOS][Fixed] - Add `nkf` and `base64` as ruby dependencies
Pull Request resolved: https://github.com/facebook/react-native/pull/55346
Reviewed By: cortinico
Differential Revision: D92147798
Pulled By: cipolleschi
fbshipit-source-id: ac06369593df2b892d343f45d3c43795c079a461
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55114
Our official [docs](https://reactnative.dev/docs/set-up-your-environment#node--watchman) require:
> Node 20.19.4 or newer
Currently, our `package.json#engines` fields express this as `"node": ">= 20.19.4"`
This is a bit imprecise because of Node's overlapping release lines - e.g. v24.0.0 is actually older than v20.19.4 (2025-07-15), and the whole v21 line was already EOL before v20.19.4.
The release *date* is relevant because Node.js frequently backports the most important updates - notably, `require(esm)` is already stable in Node 20.19 but is not unflagged in v22 until v22.12.
This makes the `package.json#engines` requirement truer to the documented requirement, dropping some old minors and EOL majors that prevent us using features included in v20.19.
Notably, `require(esm)` is stable and unflagged on all versions supported from this diff.
- v21 and v23 are EOL, so are dropped.
- v22.13 pre-dates 20.19.4 and is the first to have unflagged silent `require(esm)`
- v24.3.0 pre-dates 20.19.4 and is the first to unflag TS-stripping
- Support v25 and newer.
Changelog:
[General][Breaking] Drop support for EOL Node.js lines and old minors.
Reviewed By: cortinico, huntie
Differential Revision: D90467358
fbshipit-source-id: a5fdfb1b93a9d6cffe78eb6811ff7420ab906f44
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53837
Changelog: [Internal]
Replaces usage of Hermes built inside the React Native repository with the release published from the Hermes repo.
Reviewed By: cipolleschi
Differential Revision: D82721725
fbshipit-source-id: 357d5e2b914675ec6e60f810c382a945aa461732
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/54143
This will become the default in AGP 9.x so let's update it inside RNTester as well.
Changelog:
[Internal] [Changed] -
Reviewed By: cipolleschi
Differential Revision: D84548388
fbshipit-source-id: 755344b93204f074926e47ef2a5c980b60e9121b
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/54009
Packages haven't been bumped on main ahead of 0.83. This takes care of it.
Changelog:
[Internal] [Changed] -
Reviewed By: cipolleschi, huntie
Differential Revision: D83580515
fbshipit-source-id: 7471e77f74e3fb3b4ee6538a49369b5df1393098
Summary:
Following the [RFC](https://github.com/react-native-community/discussions-and-proposals/pull/925), this PR adds new `RCTDevMenu` configuration and extends `RCTReactNativeFactory` API for passing it to the particular `RCTHost`. The `RCTDevMenuConfiguration` includes:
- isDevMenuEnabled,
- isShakeGestureEnabled,
- areKeyboardShortcutsEnabled
## Changelog:
[IOS][ADDED] - Add new configuration for `RCTDevMenu`
<!-- Help reviewers and the release process by writing your own changelog entry.
Pick one each for the category and type tags:
[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message
For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
Pull Request resolved: https://github.com/facebook/react-native/pull/53505
Test Plan:
Tested with different configurations on `RCTDevMenuConfiguration`:
<details>
<summary>Click to view code</summary>
```objc
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.reactNativeFactory = [[RCTReactNativeFactory alloc] initWithDelegate:self];
#if USE_OSS_CODEGEN
self.dependencyProvider = [RCTAppDependencyProvider new];
#endif
RCTDevMenuConfiguration *devMenuConfiguration = [[RCTDevMenuConfiguration alloc] initWithDevMenuEnabled:true shakeGestureEnabled:false keyboardShortcutsEnabled:false];
[self.reactNativeFactory setDevMenuConfiguration:devMenuConfiguration];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self.reactNativeFactory startReactNativeWithModuleName:@"RNTesterApp"
inWindow:self.window
initialProperties:[self prepareInitialProps]
launchOptions:launchOptions];
[[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
return YES;
}
```
</details>
Run helloworld:
<img src="https://github.com/user-attachments/assets/16c35176-6fbe-498c-96fd-a0fe988a5e3c" alt="hello-world-screenshot" width="300">
Reviewed By: cipolleschi
Differential Revision: D81684275
Pulled By: coado
fbshipit-source-id: 500e170c93df25949de433970442d20c442be7f2
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53399
We currently create application template that are still using `ReactNativeHost`.
As this is a legacy arch class, we should remove it from the template ASAP so that
users can organically migrate away from it.
I will also update https://github.com/react-native-community/template with
the same changes I'm applying here.
Changelog:
[Internal] [Changed] -
Reviewed By: mdvacca
Differential Revision: D80708461
fbshipit-source-id: e0d4a1f817e6fdddd93405decf77fd115956ec51
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53281
This is still a of bumping Gradle to the latest Major (9.0)
Full list of changes is here: https://gradle.org/whats-new/gradle-9/
I don't expect any breaking changes for React Native users.
Changelog:
[Android] [Breaking] - **deps:** Gradle to 9.0
Reviewed By: cipolleschi
Differential Revision: D79445941
fbshipit-source-id: 0af495a2cc6bb4cca1e37d5f0693b77e42010df2
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53025
It's now time to say goodbye to the Legacy Architecture :')
This change hardcodes the `newArchEnabled` property to true, and warns the users
if they're attempting to set it to false.
Changelog:
[Android] [Breaking] - Remove possibility to newArchEnabled=false in 0.82
Reviewed By: cipolleschi
Differential Revision: D78560296
fbshipit-source-id: ccfc45d2f7f21cc20e063cb901d76be3d41458d6
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52887
Syncs Reac 19.1.1 into React Native.
This commit should contains the fix for:
- React owner stack in React Native
- An issue with React holding shadow node for longer than it needed
- An issue that made `startTransition` not working with React Native.
## Changelog:
[General][Changed] - Bumped React to 19.1.1
bypass-github-export-checks
Reviewed By: cortinico
Differential Revision: D79096406
fbshipit-source-id: cbb2f846b1f08ba5ff482cfed5aaddc16df075cc