Summary:
The iOS prebuild workflow (`.github/workflows/prebuild-ios-core.yml`) splits into two jobs on separate runners:
- **`build-rn-slice`** stages the hermes-ios headers during setup (`.build/artifacts/hermes/destroot/include/hermes`), but uploads only `.build/headers` + the SPM Products — **not** the hermes artifact.
- **`compose-xcframework`** (fresh runner) runs the compose (`-c` → `buildXCFrameworks`), which computed the hermes include path from `.build/artifacts/hermes/destroot/include`. That directory never exists on the compose runner, so `hermesHeaders` resolved to `null` and the hermes-header fold in `headers-compose.js` was **silently skipped**.
Net effect: the published `ReactNativeHeaders.xcframework` shipped without the `hermes/` namespace, so consumers (e.g. Expo prebuilt) couldn't resolve `<hermes/...>`. Because the value was `null` rather than a bad path, not even the existing warning fired — every nightly regressed silently.
Build-time staging, matching the artifact's self-contained design (the orphaned consumer-side sidecar + health check in `download-spm-artifacts.js` confirm the bake was intended to happen at compose time):
- **Workflow:** `compose-xcframework` now re-stages the hermes-ios headers before composing — a `Set Hermes version` step (`$GITHUB_ENV` doesn't cross jobs) and a `Stage Hermes headers` step that extracts the tarball into `.build/artifacts/hermes`. Both are guarded by the same `cache-hit` condition as the sibling steps.
- **Fail-closed guard:** the inline hermes resolution is extracted into an exported `resolveHermesHeaders(buildFolder, required)` with a `findFirst` fallback (mirroring the consumer-side stager). When a version-stamped CI cut can't find the headers it now **throws** instead of silently shipping without `hermes/`. Gated behind a new `--require-hermes` flag, which the workflow passes only when `version-type` is set — so local `-c` keeps the previous no-fold behavior.
[IOS] [FIXED] - Prebuilt `ReactNativeHeaders.xcframework` now ships the Hermes public headers so consumers resolve `<hermes/...>` out of the box
Pull Request resolved: https://github.com/react/react-native/pull/57661
Test Plan:
- New unit tests for `resolveHermesHeaders` (`__tests__/xcframework-test.js`): resolves at the standard path, resolves via the `findFirst` fallback, returns `null` when absent + not required, throws when absent + required.
- `yarn jest packages/react-native/scripts/ios-prebuild/__tests__/xcframework-test.js --no-cache -i` → 4/4 pass (red before the resolver was exported).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed By: javache
Differential Revision: D113554720
Pulled By: cipolleschi
fbshipit-source-id: 30d21240ae97978e58a95ffdfad4088ed85536d4
(cherry picked from commit 43b44ed7c3)
Summary:
`prebuild-ios-core.yml` builds the prebuilt iOS core in two jobs: **`build-rn-slice`** compiles the React binary per platform slice, and **`compose-xcframework`** runs afterwards in its **own fresh checkout**, downloads the slice artifacts, and composes the shipped `React.xcframework` + `ReactNativeHeaders.xcframework` — re-deriving the shipped *headers* from that checkout.
The "Set React Native version" step runs only in `build-rn-slice`. So the compiled **binary is stamped**, but the composed **headers are not**: the artifact ships `ReactNativeVersion.h` with the `1000.0.0` dev sentinel, internally inconsistent with its own binary (and with the npm package, which is stamped in its own publish job).
This was latent for as long as the compose job has existed — it only started breaking consumers now because the header-facades / VFS-overlay-removal work changed *which file libraries actually read*. Previously header resolution (the VFS overlay, and the `Pods/Headers/Public` symlinks of the source pods) redirected reads to the **stamped npm copy**, so the sentinel bytes in the tarball were never consumed. With real materialized headers, the prebuilt copy now wins the search path, and any library gating on `REACT_NATIVE_VERSION_MAJOR/MINOR` compiles the wrong branch. That breaks `[ios] react-native-unistyles` in nightly-tests: its `#if REACT_NATIVE_VERSION_MINOR >= 81` sees `MINOR 0` and picks a removed pre-0.81 path (`shadowNodeFromValue`).
**Fix — built-headers overlay (no re-stamp/revert).** The `build-rn-slice` job already stamps its checkout before building and uploads `.build/headers`, and the compose job already downloads it — it was just unused. `stageEntries` now takes an overlay dir and, **for `ReactNativeVersion.h` only**, prefers the built copy (stamped in the slice job) over the source sentinel. Header **layout** is still spec-derived from source (podspec inventory, collision detection, classification), and every **other** header still copies from source — so a stale build tree can never ship wrong header content, only the one build-generated version header is overlaid. No stamping of the compose checkout, no `git revert`, no cache-key desync.
The compose cache key is bumped so pre-fix (unstamped) composed artifacts cached under the old key are not served.
**Guard.** `headers-verify.js` gains `--require-stamped-version` (passed when a `version-type` is set) that hard-fails the compose verification if any composed `ReactNativeVersion.h` still contains the sentinel — turning any future regression into a red prebuild instead of silently broken community libraries.
## Changelog:
[IOS] [FIXED] - Ship a version-stamped ReactNativeVersion.h in the prebuilt iOS core artifacts instead of the 1000.0.0 dev sentinel
Pull Request resolved: https://github.com/react/react-native/pull/57603
Test Plan:
- Local compose with a stamped `ReactNativeVersion.h` seeded into `.build/headers` and the source tree left at the `1000` sentinel: all composed `ReactNativeVersion.h` copies come out stamped (overlay won), while a deliberately **stale** `.build/headers/…/TraceRecordingState.h` is correctly ignored — the composed `TraceRecordingState.h`/`HostTracingProfile.h` come from source, and other headers + module maps/umbrellas are unaffected (structural gate passes).
- Guard: composed layout with a sentinel header → `verifyVersionStamp` throws listing the offending files; stamped → `version stamp OK (N copies checked)`; no effect without the flag.
- Verified against a fresh RN-nightly app + `react-native-unistyles@3.3.0` on Xcode 26.3 (prebuilt mode) and in the Expo prebuilt harness (26.3 + 26.6): stock prebuilt headers reproduce the `shadowNodeFromValue` error; the stamped prebuilt header resolves it.
- End-to-end proof is the next nightly run: the composed tarball must carry a stamped header.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed By: javache
Differential Revision: D113005220
Pulled By: cipolleschi
fbshipit-source-id: 5fbba8bb4e84fd1458a2f4a0baa623cf613b6e3b
Summary:
Fixes the three post-release failures from the [0.87.0-rc.2 publish run](https://github.com/react/react-native/actions/runs/29775529785/):
- Keep Flow annotations in `verifyArtifactsAreOnMaven.js` as comments so `actions/github-script` can load the file with plain Node.
- Pin the Podfile lock workflow to `macos-15`, which provides the configured Xcode 16.4 version.
- Use the canonical `react/react-native` owner for release asset API operations so upload POST requests are not redirected from the former owner.
## Changelog:
[INTERNAL] [FIXED] - Fix post-release Maven verification, Podfile lock, and release asset jobs
Pull Request resolved: https://github.com/react/react-native/pull/57627
Test Plan:
```sh
node --check .github/workflow-scripts/verifyArtifactsAreOnMaven.js
node --check scripts/releases/upload-release-assets-for-dotslash.js
yarn jest .github/workflow-scripts/__tests__/verifyArtifactsAreOnMaven-test.js scripts/releases/__tests__/upload-release-assets-for-dotslash-test.js --runInBand
```
13 tests and 15 snapshots pass.
Reviewed By: zeyap
Differential Revision: D113032768
Pulled By: cipolleschi
fbshipit-source-id: df5f493603e6c25157fd7660b54aa409dcb742e7
Summary:
The prebuilt `React.xcframework` previously relied on a Clang VFS overlay (`React-VFS.yaml`) to make headers importable, because the headers were laid out in CocoaPods-style namespaced folders rather than standard framework conventions. The overlay had to be generated at build time, re-resolved at pod-install time per slice, and injected as `-ivfsoverlay` flags into every Obj-C, C++, and Swift compile (including aggregate and third-party pod targets).
This is fragile, hard to reason about, and incompatible with SwiftPM consumption.
This PR removes the VFS overlay entirely and resolves headers through standard framework/header-search-path mechanics instead.
**Headers are now emitted into the artifact according to an explicit, executable spec:**
- **`React.xcframework`** — each slice's `React.framework` carries every `<React/...>` header plus a framework module map, so `#import <React/...>` and `import React` resolve through `FRAMEWORK_SEARCH_PATHS` automatically.
- **`ReactNativeHeaders.xcframework`** (new, headers-only) — carries every other namespace (`<react/...>`, `<yoga/...>`, `folly`, `glog`, …), shipped alongside in the prebuilt tarball and exposed via a single header search path.
- This makes `ReactNativeDependencies` binary-only.
No clang VFS overlay, no per-target `-ivfsoverlay` flags. The layout is driven by a single source of truth (`headers-spec.js`, rules R1–R11) that both the prebuild compose step and downstream SwiftPM tooling derive from, so the shipped header set cannot drift from the spec.
Source headers are byte-identical to the repo — the only consumer-facing change needed is bare-form angle includes (`#import <RCTAppDelegate.h>` → `#import <React/RCTAppDelegate.h>`).
**Consumer surfaces the flattened layout initially dropped are restored** (validated against Expo and community Fabric modules):
- Private headers (`RCTBridge+Private.h` + the Fabric `RCTComponentView*` family) are exposed in the `React` module map — modular where safe, `textual` where they reach C++ — so frameworks like Expo compile unchanged, incl. Swift access to `RCTBridge.moduleRegistry`.
- `React_RCTAppDelegate-umbrella.h` is re-emitted (derived from the live header set) for consumers probing it via `__has_include`.
- Sources shipping under multiple include spellings (`React/X.h` + legacy `CoreModules/…`, `RCTImage/…`, bare aliases — 116 today) keep content at ONE module-owned spelling; other spellings become generated redirect shims, so `-fmodules` consumers cannot hit duplicate declarations.
- The `React-RCTFabric` facade re-vends `RCTFabricComponentsPlugins.h` at `header_dir "React"`, keeping community Fabric modules' quoted `#import "RCTFabricComponentsPlugins.h"` working as with source pods.
**The layout is verified at generator time** (`headers-verify.js`, runs in the prebuild compose CI job): unresolvable includes ratchet against a committed baseline, composed module maps/umbrellas must byte-match the spec render, and consumer-shaped compile smokes must pass (the `React` module, every namespace module, an Expo-shaped ObjC++ fixture, and a Swift `moduleRegistry` fixture). Fail-closed guards cover header collisions, allowlist drift, and missing OR undeclared third-party deps namespaces (the latter surfaced `SocketRocket`, which is deliberately NOT relocated — the real pod vends it, and textual copies collide under `use_frameworks`; the gate asserts its absence).
**Key changes**
- **New**: `headers-spec.js` (the executable layout contract, R1–R11), `headers-compose.js` (emitter for both xcframeworks), `headers-inventory.js` (podspec-driven header classifier feeding the spec + a diagnostic manifest), `headers-verify.js` (generator-time gate + CI step), `__docs__/headers-rules.md` (rules + rationale).
- **Removed**: `vfs.js`, VFS types in `types.js`, and the VFS processing/flag-injection paths in `rncore.rb` and `xcframework.js`.
- **Updated**: `React-Core-prebuilt.podspec` (vends both xcframeworks, flattens `ReactNativeHeaders` headers into `Headers/` via `prepare_command`, fails closed on incomplete tarballs), `rncore.rb` / `react_native_pods.rb` (header search path instead of overlay flags), `prebuild-ios-core.yml` (core tarball ships both xcframeworks; compose job verifies the composed headers), README (VFS docs replaced with the new model).
- Added facades to the Podspecs that shouldn't be in use when running using precompiled frameworks to satisfy dependencies as empty pod-specs (with the single `RCTFabricComponentsPlugins.h` re-vend exception noted above).
## Changelog:
[IOS] [CHANGED] - Remove the Clang VFS overlay from prebuilt React Native Core; resolve headers via React.xcframework + a new headers-only ReactNativeHeaders.xcframework
Pull Request resolved: https://github.com/react/react-native/pull/57285
Test Plan:
- [x] rn-tester builds against the prebuilt `React-Core-prebuilt` pod (Debug + Release) with no `-ivfsoverlay` flags present in the generated xcconfigs.
- [x] rn-tester builds against React native source code (without any prebuilt artifacts)
- [x] `#import <React/...>`, `import React;`, and the relocated namespaces (`<react/...>`, `<yoga/...>`, `folly`/`glog`) all resolve.
- [x] Prebuilt tarball contains both `React.xcframework` and `ReactNativeHeaders.xcframework`; pod install flattens headers into `React-Core-prebuilt/Headers`.
- [x] Switch RN-tester between Debug/Release and verify that both `React.xcframework` and `ReactNativeHeaders.xcframework` are changed between debug and release correctly.
- [x] `headers-verify.js` gate green on Debug and Release composes (`-Werror=non-modular-include-in-framework-module` never trips in consumer builds).
- [x] `private/helloworld` builds against the prebuilt core (CocoaPods path).
- [x] Expo SDK compiles against the prebuilt artifacts (private headers, `React_RCTAppDelegate` umbrella probe, Fabric quoted imports).
Reviewed By: fabriziocucci
Differential Revision: D111448598
Pulled By: cipolleschi
fbshipit-source-id: 72bc2f37765ad425722161a038e410ba976858a5
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57490
See [**RFC0894: Removing deep imports from react-native**](https://github.com/react-native-community/discussions-and-proposals/pull/894)
This is the **big switch** to enable the Strict TypeScript API (generated types + single index entry point) by default in React Native.
**Opt-in → opt-out**
After this change, the main `react-native` package resolves its `"types"` entry points only to `types_generated/index.d.ts` — with no other subpaths available.
The new `"react-native-legacy-deep-imports"` condition maps to legacy `types/` and `Libraries/*.d.ts` sources.
**Impact limitation**: For this stage of rollout, the `"default"` condition continues to resolve to source files. Only TypeScript is affected.
**How to opt out**
Opposite of today's opt-in, which we will update in [the docs](https://reactnative.dev/docs/strict-typescript-api). Again, the only impact area today is **TypeScript**.
```json5
// tsconfig.json
{
"extends": "react-native/typescript-config",
"compilerOptions": {
...
"customConditions": ["react-native-legacy-deep-imports"]
}
}
```
**Other changes**
- Drop `react-native/typescript-config/strict` entry point, update README.
- Update `__typetests__`.
**Rollout plan**
**Target release: 0.87**. This and the contributing stack will be cherry picked for RC1.
- We've conducted testing against 100+ real Expo codebases, giving us the confidence that we've reduced breaking changes enough that the vast majority of RN codebases can migrate.
- The Strict API includes a number of **intentional breaking changes**, and docs have been kept up to date.
- We're shipping a `/migrate-to-strict-api` skill to migrate via agents, see https://github.com/react-native-community/skills/pull/3.
**What's improved since 0.80?**
Since the initial opt-in launch of the Strict API in 0.80, we've been making continuous improvements over the last year to get our generated types into a widely launchable state.
Most notably:
- 21+ new/updated root APIs and fixes due to community feedback ([discussion](https://github.com/react-native-community/discussions-and-proposals/discussions/893), [PRs](https://github.com/react/react-native/pulls?q=is%3Apr%20label%3A%22JS%20API%20stabilization%20(1.0)%22%20is%3Aclosed)).
- Upstream encapsulation blocker in TypeScript, fixed in 6.0 (https://github.com/react/react-native/issues/53565).
- Tailwind/Uniwind compatibility (`interface` types for props).
- `*Instance` ref type exports for all built-in components (https://github.com/react-native-community/discussions-and-proposals/pull/1003).
- Fixes to previously mistyped, high impact APIs, such as `Appearance`.
- New subpath entry points for `asset-registry`, `setup-env`, and others.
- Refinements to doc comments/type translation build.
**Rollback plan**
Revert this diff.
IMPORTANT: We'll adopt a policy of **super-eager rollback**, if there are any unsolvable issues during the RC phase.
Changelog:
[General][Breaking] - React Native's default JavaScript API is now the [Strict TypeScript API](https://reactnative.dev/docs/strict-typescript-api). Use `customConditions: ["react-native-legacy-deep-imports"]` to opt out.
Reviewed By: cortinico
Differential Revision: D110458670
fbshipit-source-id: 4b0e0b458a5f895f783d6d936e7b11ccff2df076
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57310
Add `AppIcon.icon` file (Icon Composer) for macOS 26 Tahoe. Also rename previous `.icns` file for consistency.
`electron/packager` is updated to `^20.0.0` (`.icon` support was added in `18.4.0`).
**Notes**
- This change ensures the Icon Composer source is part of the codebase (following above Electron packager support which came in March).
Changelog:
[General][Changed] - **React Native DevTools**: Add macOS 26/27 app icon
Reviewed By: robhogan
Differential Revision: D97292364
fbshipit-source-id: ba1c34175a95da8c2860142d9db0c4d98d3f6de0
Summary:
This reverts the runner changes from https://github.com/react/react-native/issues/57216, which moved the Android CI jobs from the dedicated `4-core-ubuntu` / `8-core-ubuntu` runners onto the standard `ubuntu-latest` runners.
I'm opening this (as a draft) to **see if we can speed up the RN runners** — i.e. to measure whether going back to the larger dedicated runners gives us faster CI than `ubuntu-latest`. This is an experiment to compare timings.
### What's reverted
- `e2e-android-rntester.yml`: `ubuntu-latest` → `4-core-ubuntu`
- `e2e-android-templateapp.yml`: `ubuntu-latest` → `4-core-ubuntu`
- `fantom-tests.yml`: `ubuntu-latest` → `8-core-ubuntu`
- `test-all.yml`: `build_fantom_runner`, `build_android`, `build_npm_package` → `8-core-ubuntu`; `test_android_helloworld` → `4-core-ubuntu`
### Not reverted (drift since https://github.com/react/react-native/issues/57216)
- `nightly.yml` was deleted on main (consolidated into `publish-npm.yml`).
- `publish-npm.yml` was fully restructured on main (the old `publish-react-native` reusable job no longer exists).
These two are release/nightly jobs rather than the per-PR CI that determines runner speed, so they're intentionally left untouched.
Changelog:
[INTERNAL] -
## Changelog
[INTERNAL] -
Pull Request resolved: https://github.com/react/react-native/pull/57323
Test Plan: CI — compare job durations against `ubuntu-latest`.
Reviewed By: fabriziocucci
Differential Revision: D109808150
Pulled By: cortinico
fbshipit-source-id: 694eba516f0d42ef733e729b23534f09dfe8548c
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57286
We currently have a mix of quote styles in `.yml` files (AI summary below). This applies prettier and reformats everything to single quotes to align with defaults.
Also fixes a couple of cases of over-indentation.
```
Single-quotes only (0 double-quoted scalars):
analyze-pr.yml
— 12 single, 0 double
api-changes.yml
— 3 single, 0 double
check-for-reproducer.yml
— 4 single, 0 double
retry-workflow.yml
— 1 single, 0 double
Single-quote predominant > double:
autorebase.yml 2 vs 1
create-draft-release.yml 8 vs 2
generate-changelog.yml 3 vs 2
on-issue-labeled.yml 7 vs 2
prebuild-ios-core.yml 59 vs 17
prebuild-ios-dependencies.yml 39 vs 1
stale-bot.yml 18 vs 15
test-all.yml 70 vs 27
Double-quote predominant > single:
bump-podfile-lock.yml 1 vs 10
create-release.yml 3 vs 12
e2e-android-rntester.yml 2 vs 6
e2e-android-templateapp.yml 6 vs 13
e2e-ios-rntester.yml 2 vs 7
e2e-ios-templateapp.yml 2 vs 18
fantom-tests.yml 2 vs 7
monitor-new-issues.yml 3 vs 12
publish-npm.yml 42 vs 50
validate-cxx-api-snapshots.yml 2 vs 23
validate-dotslash-artifacts.yml 2 vs 5
Tie / 1-1:
cache-reaper.yml 1 vs 1
close-pr.yml 1 vs 1
needs-attention.yml 2 vs 2
All files contain single quotes somewhere, but only those 4 are single-quote-exclusive. Most CI-heavy workflows — bump, create-release, e2e-, fantom, monitor, publish-npm, validate- — lean double-quoted, while the pr/issue automation, prebuild ios, test-all, and stale-bot lean single-quoted.
```
Changelog: [Internal]
___
Differential Revision: D109151683
fbshipit-source-id: 24391e906c0dd92fe402224089dce8bb2068b4d9
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57269
Trusted publish support requires `npm` CLI version >=11.5.1 ([docs](https://docs.npmjs.com/trusted-publishers)), which is bundled with Node 24.
This bumps the Node version for just those jobs that call `npm publish`.
Changelog: [Internal]
Reviewed By: fabriziocucci
Differential Revision: D109009971
fbshipit-source-id: 6e7f412c6da0e5e5749a29e789f8c2e67610d7b0
Summary:
## Problem
npm Trusted Publishing matches the `workflow_ref` OIDC claim, which is always the top-level workflow filename. npm allows only ONE trusted publisher per package. The prior migration (https://github.com/react/react-native/issues/57099) used `workflow_call` to route all publishes through `publish-npm.yml`, but `workflow_ref` resolves to the *caller* (e.g. `nightly.yml`), not the reusable child, so the Trusted Publisher entry for `publish-npm.yml` never matches.
## Solution
Merge all three publish entry points into `publish-npm.yml` itself, triggered by all three event types:
- `push.tags: v0.*` -> release mode (was publish-release.yml)
- `schedule + workflow_dispatch` -> nightly mode (was nightly.yml)
- `push.branches: main, *-stable` -> bumped-packages mode (was publish-bumped-packages.yml)
A `determine_mode` job inspects the trigger and sets the mode. Downstream jobs use conditional `if:` expressions to run only the relevant build/publish steps.
Since `publish-npm.yml` is now always the top-level workflow, `workflow_ref` always resolves to `publish-npm.yml`, which matches what's already configured on npm.
Changelog: [Internal]
Pull Request resolved: https://github.com/react/react-native/pull/57255
Reviewed By: cortinico
Differential Revision: D108894981
Pulled By: robhogan
fbshipit-source-id: 743d5b75cbce1eedfec681ec98fd17332f05f14d
Summary:
build_android is currently timing out - this should unblock it for now till we find a different solution.
## Changelog:
[INTERNAL] -
Pull Request resolved: https://github.com/react/react-native/pull/57216
Test Plan: CI
Reviewed By: huntie
Differential Revision: D108744449
Pulled By: cortinico
fbshipit-source-id: 4b14252889c3d9ebcb4ad2135839233e103355d7
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57167
Update GitHub Actions workflow files to reflect React Native's migration from `facebook/react-native` to `react/react-native`.
Changes the fork-prevention guards (`github.repository == 'facebook/react-native'`) to use the new org across 17 workflow files (28 occurrences total), plus updates the `repo_owner` parameter in the issue monitoring workflow.
Changelog: [Internal]
Reviewed By: fabriziocucci
Differential Revision: D108246445
fbshipit-source-id: 010631838a05e366da525aa765d3ea4376f9d145
Summary:
Adds a temporary debug step to both jobs of the reusable npm publish workflow that requests the GitHub Actions OIDC token (npm audience) and prints its decoded claims. This makes it possible to compare the token claims against the npm Trusted Publisher configuration when the OIDC exchange fails. Only the decoded claims are printed, never the raw token.
Changelog: [Internal]
bypass-github-export-checks
Reviewed By: cortinico, cipolleschi
Differential Revision: D108108630
fbshipit-source-id: 6ae8be8c9e9e2e611b6941b336230a21f876e134
Summary:
This makes the shell to use escape interpretation by setting `echo -e "..."`. For zsh shell, this often works out of the box. For other shells like bash, we may need to set it explicitly.
## 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
-->
[INTERNAL] [FIXED] - allow escape interpretation for shells
Pull Request resolved: https://github.com/facebook/react-native/pull/57114
Test Plan:
- CI Passes
- Verified Locally on template app
https://github.com/user-attachments/assets/4c8c6bf7-1cf2-4bd8-b094-651c44578ae0
Reviewed By: cipolleschi
Differential Revision: D107904889
Pulled By: cortinico
fbshipit-source-id: 2222f589ecc149a82d5067e0a2198b9c1a17ffcb
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/57099
Replaces the long-lived `GHA_NPM_TOKEN` automation token with npm
Trusted Publishing (OIDC) for every `npm publish` invoked from this
repo's GitHub Actions.
Why a reusable workflow:
npmjs.com Trusted Publishing accepts only ONE (org, repo,
workflow_filename, environment) tuple per package. Today, packages
are published from multiple workflow files:
- `react-native` from publish-release.yml + nightly.yml
- every `react-native/*` from nightly.yml + publish-bumped-packages.yml
A naive per-workflow OIDC migration would require two Trusted
Publisher entries per package, which npm doesn't support. Instead,
this diff funnels every `npm publish` through one new file —
`.github/workflows/publish-npm.yml` — invoked via `workflow_call`
from the existing top-level workflows. The OIDC `job_workflow_ref`
claim therefore always resolves to `publish-npm.yml`, so each
package needs exactly one Trusted Publisher entry pointing here.
What changes:
* New `.github/workflows/publish-npm.yml`: reusable workflow with a
`mode` input. `mode: react-native` runs the full Android + iOS
prebuilt + JS build path (used by release & nightly, publishes
`react-native` and — in nightly mode — every `react-native/*`
package via `scripts/releases-ci/publish-npm.js`). `mode:
monorepo-packages` runs only the JS build and publishes the
delta-bumped packages via
`scripts/releases-ci/publish-updated-packages.js` (used by
publish-bumped-packages.yml). Both jobs grant `id-token: write` so
the npm CLI can mint the OIDC token for Trusted Publishing.
* `.github/workflows/publish-release.yml`: replace the
`build_npm_package` job's inline build/publish steps with a
`uses: ./.github/workflows/publish-npm.yml` call. The
template-publish, rn-diff-purge, npm-verify, and Maven-verify
steps move into a new `post_publish` follow-up job that
`needs: [build_npm_package]`. Drops `GHA_NPM_TOKEN` from the env.
* `.github/workflows/nightly.yml`: same — `build_npm_package` now
delegates to the reusable workflow. Drops `GHA_NPM_TOKEN` and the
obsolete `Verify NPM token` precheck (Trusted Publishing has no
pre-mintable token to validate; failures surface at `npm publish`
time).
* `.github/workflows/publish-bumped-packages.yml`: shrinks to a thin
trigger wrapper that calls the reusable workflow with
`mode: monorepo-packages`.
* `.github/workflows/create-release.yml`: drop the obsolete `Verify
NPM token` step.
* `.github/actions/build-npm-package`: drop the `gha-npm-token`
input and the `Set npm credentials` step that wrote `_authToken`.
Pass `registry-url: https://registry.npmjs.org` to setup-node so
`actions/setup-node@v6` writes a `.npmrc` configured to consume
the OIDC token at publish time.
* `.github/actions/setup-node`: thread a new `registry-url` input
through to `actions/setup-node@v6`.
The publish scripts themselves (`scripts/releases-ci/publish-npm.js`,
`scripts/releases-ci/publish-updated-packages.js`,
`scripts/releases/utils/npm-utils.js`) are unchanged: they shell out
to plain `npm publish`, which performs the OIDC exchange transparently
when it sees a GitHub Actions OIDC environment and a Trusted Publisher
configured for the package on npmjs.com.
Note: this diff only changes the workflow definitions. Each package
on npmjs.com must additionally be configured with a Trusted Publisher
pointing at:
- org: facebook
- repo: react-native
- workflow filename: publish-npm.yml
- environment: npm-publish
The npm CLI's OIDC exchange returns 404 until that registry-side
config is in place. Trusted Publisher entries are additive on
npmjs.com (don't enable "Require Trusted Publishing" yet) so the
existing token-based flow keeps working through the cutover. See the
stack landing notes for the full package list and UI steps.
Backport: this also needs picking back to `*-stable` branches before
"Require Trusted Publishing" is enabled on any package, since
GitHub Actions runs the workflow file from the ref that triggers it.
Changelog:
[Internal]
Reviewed By: cortinico, cipolleschi
Differential Revision: D107805971
fbshipit-source-id: 7a360dff9666c4b0952504331d26c0af74148789
Summary:
This fixes the failing CI jobs on main for `template` testing. The job fails as they echo `react.internal.mavenLocalRepo=...` to the `gradle.properties` of template test project. As a result of which the `gradle.properties` look like below:
```properties
android.builtInKotlin=false
android.newDsl=falsereact.internal.mavenLocalRepo=...
```
To fix it we add a line break in the `echo` command.
## 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
-->
[INTERNAL] [FIXED] - add line break to gradle.properties for template testing
Pull Request resolved: https://github.com/facebook/react-native/pull/57107
Test Plan:
- CI Passing
- Verified Locally
Reviewed By: cortinico
Differential Revision: D107880136
Pulled By: cipolleschi
fbshipit-source-id: 81cf2fe53c1c2285f79db538aa5aa3cb745f796d
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:
Pull Request resolved: https://github.com/facebook/react-native/pull/55915
Addresses a design gap with conditional Android/iOS test runs ([#55449](https://github.com/facebook/react-native/pull/55449)). `build_npm_package` depended on both Android and iOS prebuilds, causing platform-specific E2E tests to be skipped unnecessarily.
Fixed by allowing `build_npm_package` to optionally skip bundling Apple prebuits, and updating the dependencies of the E2E test jobs.
Changelog: [Internal]
Reviewed By: cortinico
Differential Revision: D95218910
fbshipit-source-id: 29dd91b773a567ccf83c1888250493773232140d
Summary:
Pins the default `GITHUB_TOKEN` to `contents: read` on 2 workflows in `.github/workflows/` that don't call a GitHub API beyond the initial checkout.
The following files were left implicit because they reference `GITHUB_TOKEN` / use a write-scope action / trigger on `pull_request_target`. Those scopes are best declared by maintainers: `cache-reaper.yml`, `check-for-reproducer.yml`, `retry-workflow.yml`, `validate-dotslash-artifacts.yml`.
## Why
CVE-2025-30066 (March 2025 `tj-actions/changed-files` supply-chain compromise) exfiltrated `GITHUB_TOKEN` from workflow logs. Pinning per workflow caps runtime authority irrespective of the repo or org default, gives drift protection if the default ever widens, and is credited per-file by the OpenSSF Scorecard `Token-Permissions` check.
YAML validated locally with `yaml.safe_load` on each touched file.
## Changelog
[Internal] [Changed] -
Pull Request resolved: https://github.com/facebook/react-native/pull/56834
Reviewed By: cipolleschi
Differential Revision: D105294446
Pulled By: cortinico
fbshipit-source-id: c90e885345f7b49d6c3ccfd73fdbd7ce8eebe4a1
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56756
The use-hermes-nightly boolean input of prebuild-ios-core.yml was misleadingly named.
It controls whether to use the latest prebuilt Hermes from npm's latest-v1 dist-tag
(not a 'nightly' build). Rename:
- prebuild-ios-core.yml input: use-hermes-nightly -> use-hermes-prebuilt
- Update description of the input
- Update comment to move the TODO note inline
- Update callers in nightly.yml and test-all.yml
## Changelog:
[Internal] -
Reviewed By: cortinico
Differential Revision: D104649628
fbshipit-source-id: 71c75b07caebfe5e7d03e80d47cefba883843c9a
Summary:
- Adds retry jobs (up to 2 retries) for all 4 E2E test jobs on PRs to handle flakiness
- Original E2E jobs use `continue-on-error` on PRs so failures don't block the workflow; on `main`, behavior is unchanged and the existing `rerun-failed-jobs` mechanism continues to work
- Each retry runs on a fresh runner (addressing environment-level flakes) and is triggered via step-level outcome captured as a job output
- Added `overwrite: true` to artifact uploads in maestro composite actions so retry jobs don't conflict on artifact names
### How it works
- **On PRs:** E2E job fails → `retry_1` triggers → if that fails → `retry_2` triggers. All have `continue-on-error` so the workflow stays green.
- **On `main`:** `continue-on-error` is `false`, retry jobs are skipped (PR-only), and `rerun-failed-jobs` handles retries as before.
### Known limitation
Since these are matrix jobs (Debug/Release), the job output uses the last-to-complete matrix combination's value. If only one flavor fails and the passing one finishes last, the retry may not trigger. In the common flakiness pattern (environment-level issues), both flavors tend to be affected, so this works well in practice.
## Changelog:
[Internal] - Add E2E test retry jobs for PRs
Pull Request resolved: https://github.com/facebook/react-native/pull/56581
Test Plan:
- CI will validate the workflow syntax
- On a PR where E2E tests pass: retry jobs should be skipped
- On a PR where E2E tests fail due to flakiness: retry jobs should trigger and (ideally) pass on a fresh runner
- On pushes to `main`: existing `rerun-failed-jobs` behavior is preserved (retry jobs are skipped)
Reviewed By: cortinico
Differential Revision: D102327900
Pulled By: cipolleschi
fbshipit-source-id: e257e012357fdba442c302085ceed0667355272e
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56503
Changelog: [Internal]
Changes the signals pointing out C++ api snapshot not being updated to be blocking.
Commits the new baseline snapshots
Reviewed By: cipolleschi, cortinico
Differential Revision: D101617655
fbshipit-source-id: 8836cb55292ab2e3fa0b696d289f9bd0daf46dec
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56502
Adds an NPM token validation step to the `build_npm_package` job of the
React Native nightly workflow. Mirrors the same check we recently added
to `create-release.yml` and the Hermes `rn-build-hermes.yml` workflows
so we fail fast (with a clear message) instead of failing partway
through the publish step when the token is expired or missing.
## Changelog:
[Internal] -
Reviewed By: fabriziocucci
Differential Revision: D101594276
fbshipit-source-id: bb0fbddf5eba921f4184117dc29c7cc9e911a00e
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56501
Add an early NPM token validation step to the create-release workflow.
This runs `npm whoami` right after checkout to fail fast if the token is
expired or invalid, avoiding wasted CI time on a release that would fail
at the publish step.
The step gracefully skips when no token is present (e.g. fork PRs).
## Changelog:
[Internal] -
Reviewed By: christophpurrer
Differential Revision: D101377190
fbshipit-source-id: 53243a24649f86d274b2ea31793333fd815e69cb
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56042
Adds CI workflow for validating whether the current C++ API snapshot is equivalent with the generated one.
Changelog:
[Internal]
Reviewed By: cortinico
Differential Revision: D95963515
fbshipit-source-id: 4629999e2d09dbdcfb9fd3e6308a9254dd4f0237
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56172
Changelog: [Internal]
Removes obsolete workflows which were testing Hermes V1 integration. Since Hermes V1 is the default now, those are no longer needed.
Reviewed By: cortinico
Differential Revision: D97464853
fbshipit-source-id: df3394548e6e1b3cf854674b2371cf31be935c81
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/54729
Changelog: [Internal]
- Created new build-fantom-runner action to compile the Fantom runner binary
- Modified run-fantom-tests action to download and use pre-built binary
- Updated test-all.yml workflow to run build and test as separate jobs
- Removed build dependencies and ccache configuration from test job
Reviewed By: cortinico
Differential Revision: D88012198
fbshipit-source-id: cd1c91b18cccc3c62b9edbcbeb131e80551369f1
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56005
Changelog: [Internal]
The build_debugger_shell CI job was failing because build-binary.js
expects pkg.main to start with ./dist/, but without --prepack the
prepack.js script never runs, so main stays as ./src/index.js.
This was caused by a series of PRs:
- PR #54857 refactored debugger-shell/package.json to use the
publishConfig pattern, moving main from ./dist/index.js to
./src/index.js.
- PR #55415 added the --prepack flag to build.js to support this.
- PR #55416 added the build_debugger_shell CI job but ran yarn build
without --prepack.
The fix passes --prepack to yarn build so that prepack.js rewrites
package.json main to ./dist/index.js before build-binary.js runs.
Reviewed By: huntie
Differential Revision: D95818417
fbshipit-source-id: 03c8340c415960c3937b13bdea3952798d2d420e
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55917
As a defensive initial design, conditional Android/iOS job runs for `test-all` were intended to be scoped to PRs only, however required a missing `== 'true'` match specifier.
Fixing this will help us catch rare integration-conflict failures on `main`, at the appropriate commit.
Changelog: [Internal]
Reviewed By: cortinico
Differential Revision: D95042221
fbshipit-source-id: ffa23651c9b8c18939ccbd7ab2279243690944d2
Summary:
This updates the CI to use `REACT_NATIVE_DOWNLOADS_DIR` so the directory where the C++ dependencies are consumed from is always the same.
This works in conjuction with:
- https://github.com/react-native-community/docker-android/pull/248
## Changelog:
[INTERNAL] -
Pull Request resolved: https://github.com/facebook/react-native/pull/55567
Test Plan: CI
Reviewed By: cipolleschi
Differential Revision: D93417423
Pulled By: cortinico
fbshipit-source-id: 75664e7d48cbba2483e05c023ac0201fb768ef35
Summary:
This reapplies the same changes from https://github.com/facebook/react-native/issues/55453 to further jobs that were missing it.
This should unblock nightlies that are currently failing.
## Changelog:
[INTERNAL] -
Pull Request resolved: https://github.com/facebook/react-native/pull/55564
Test Plan: CI
Reviewed By: cipolleschi
Differential Revision: D93408173
Pulled By: cortinico
fbshipit-source-id: 11823daeb8ef95fb5b9b8942f23f33353b6d6b6b
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55449
Further workflow optimisation after D92417918. Aims to improve speed of CI signals and reduce costs by excluding Android and iOS specific jobs when a PR contains changes exclusively within native code to one platform.
Changelog: [Internal]
Reviewed By: NickGerleman
Differential Revision: D92512983
fbshipit-source-id: feb67ce140014352219ae2b5720fc819ec5e1c11
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55469
Rename workflow job IDs from kebab-case to snake_case and update workflow name to match convention.
Changelog: [General][Changed] - rename workflow job IDs from kebab-case to snake_case
Reviewed By: huntie
Differential Revision: D92697078
fbshipit-source-id: bc8c99b6807997fe625d1f7921b3664992697b36
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55385
Now that all Danger.js checks have been migrated to native GitHub Actions in the `annotate-pr.yml` workflow, this removes the deprecated Danger infrastructure:
- Deletes `.github/workflows/danger-pr.yml` workflow
- Deletes `private/react-native-bots/dangerfile.js`
- Removes `danger` npm dependency from `react-native-bots/package.json`
The functionality previously provided by Danger.js is now handled by:
- **API diff detection**: `diff-js-api-changes` action
- **PR body validation**: `validatePRBody.js` script (summary, test plan, changelog checks)
- **Branch targeting**: `checkBranchTarget.js` script (validates target branch, adds "Pick Request" label)
- **PR commenting**: `post-pr-comment` action
This simplifies the CI pipeline by removing the third-party Danger dependency and consolidating PR annotation logic into maintainable GitHub Actions workflows.
Changelog: [Internal]
Reviewed By: huntie
Differential Revision: D91695886
fbshipit-source-id: c88001ef75d16c4709c7972add141db0df3b5a30
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55383
Adds a branch targeting validation that replaces the equivalent Danger.js check.
The check validates that PRs target either `main` or a `-stable` branch, and
automatically adds the "Pick Request" label when targeting stable branches.
- Created `checkBranchTarget.js` - pure function returning validation message
- Added check step to `annotate-pr.yml` that calls the JS and adds labels
- Added `issues: write` permission for label functionality
Changelog: [Internal]
Reviewed By: huntie
Differential Revision: D91685081
fbshipit-source-id: 87e7124f7d825b51cb791dc94720c487ff95d414
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55382
This adds a `validatePRBody.js` script that checks pull request descriptions for required sections as part of a new `analyze-pr.yml` workflow that will replace part of the Danger-pr workflow.
The validation includes:
- **Description length check**: Fails if the PR body is missing or less than 50 characters
- **Summary section check**: Warns if the PR lacks a "## Summary" section
- **Test plan check**: Warns if the PR lacks a "## Test Plan" section
- **Changelog validation**: failing if missing or invalid
Key behaviors:
- Phabricator-sourced PRs (detected via "Differential Revision:" in body) skip summary, test plan, and changelog validation since these are enforced differently
- Validation messages use GitHub's `[!WARNING]` and `[!CAUTION]` callout syntax for clear visual feedback
- The workflow fails (via `core.setFailed`) when any required check fails
- Messages are passed to `postPRComment` alongside API changes for consolidated PR comments
This aims to mimic relevant parts of dangerfile.js
Changelog: [Internal]
Reviewed By: huntie
Differential Revision: D91158803
fbshipit-source-id: 2304251d18f9fc8bf9a29e536fff2d979573bd86
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55341
Changelog:
[INTERNAL] [CHANGED] - Add api-changes.yml workflow to replace danger-pr for detecting changes in the js api
The workflow:
- Triggers on `pull_request_target` for opened, edited, reopened, and synchronize events
- Checks out the main branch (for security, using trusted code)
- Runs the `diff-js-api-changes` action to detect API changes
- Posts a PR comment using the generic `post-pr-comment` action
The PR comment script creates, updates, or deletes a bot comment based on whether
there are any sections to report, using a marker to identify existing bot comments.
Reviewed By: huntie
Differential Revision: D90991845
fbshipit-source-id: 753475a7c24df8bc581b2ab47bfad1f5551c823c
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55429
Completes this stack of diffs focused around the organisation and efficiency of the `test-all` GitHub Actions workflow.
**Changed**
All root jobs (excluding `lint`), when running against a PR, now depend on the initial `check_code_changes` job. This matches any non-Markdown, non docs change — meaning trivial PRs such as changelog updates should now avoid unnecessarily running the expensive parts of this workflow.
IMPORTANT: This is a significant change at the root of the workflow that contributes to our prebuilts/release infra — please review carefully.
**The new `any_code_change` filter**
Extremely defensive:
- Matches `'!**/__docs__/**', '!**/*.md'` only.
- Also **always** sets `any_code_change` to true if on `main`, a release branch, or on a workflow dispatch (`github.event_name != 'pull_request'`).
Changelog: [Internal]
Reviewed By: cortinico
Differential Revision: D92417918
fbshipit-source-id: ca5bc41a3c11569b8f69062ab66eeeab89d30089
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55428
With a lighter weight `lint` job, make this blocking for `test_js` runs. The combined `lint` + `test_js` execution time in series remains far less than the native build+test jobs.
Changelog: [Internal]
Reviewed By: cortinico
Differential Revision: D92417805
fbshipit-source-id: 05832257518c8141ca0955f18e740f752e675d4d
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55427
Following previous diffs, this now promotes the `lint` action to direct job steps.
**Motivation**
This has the advantage of making sub-steps in the GitHub UI visible, rather than running the 7 lint steps under a single banner.
I feel this is justified in the case of `lint`, although increasing the size of `.github/workflowsl/test-all.yml` slightly, because:
- Each step in this job is a distinct tool run with differing output, rather than one logical "action" — and this grouped output is therefore useful to the user.
- Lint failures are reasonably frequent for users, emphasising the above.
Changelog: [Internal]
Reviewed By: cortinico
Differential Revision: D92417807
fbshipit-source-id: ed24cfa2e581a528e80faec4128d280926f56613