React Native is Meta's open-source framework for building native mobile applications on iOS and Android using JavaScript and React. This guide covers the full monorepo architecture, build systems, native rendering pipeline, module systems, debugging infrastructure, and operational procedures for administrators, platform engineers, and contributors working at scale with React Native 0.86.0-main.
Version: 0.86.0-main
Source commit: ba204fa
Repository size: 6,915 files, 9.4 million characters
Package manager: Yarn 1.22.22 (workspace monorepo)
1. Architecture Overview
1.1 High-Level System Architecture
React Native bridges JavaScript application code to native platform APIs through a layered architecture that has evolved from an asynchronous message bridge to a synchronous C++ interface layer (JSI) with direct native invocations.
┌─────────────────────────────────────────────────────────────┐
│ Application Layer │
│ React Components (JSX) → Props → State → Effects │
└────────────────────────────┬────────────────────────────────┘
│
┌────────────────────────────▼────────────────────────────────┐
│ JavaScript Layer │
│ React Reconciler → Virtual Tree Diffing → Mutations │
│ Libraries/ (Core, Components, Network, Lists, LogBox) │
│ src/private/ (DOM events, XHR, MutationObserver, etc.) │
└────────────────────────────┬────────────────────────────────┘
│ JSI (synchronous C++ bridge)
┌────────────────────────────▼────────────────────────────────┐
│ C++ Shared Core (ReactCommon) │
│ │
│ ┌───────────┐ ┌────────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Fabric │ │ Turbo │ │ Yoga │ │ JSI │ │
│ │ Renderer │ │ Modules │ │ Layout │ │ Runtime │ │
│ │ (82+9 │ │ (codegen │ │ (C++ │ │ (engine │ │
│ │ files, │ │ driven, │ │ flex- │ │ agno- │ │
│ │ 272K) │ │ lazy) │ │ box) │ │ stic) │ │
│ └─────┬──────┘ └─────┬──────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ ┌─────▼───────────────▼──────────────▼─────────────▼──────┐ │
│ │ jsinspector │ nativemodule │ hermes integration │ │
│ └─────────────────────────────────────────────────────────┘ │
└────────┬──────────────────────────────────────┬─────────────┘
│ │
┌────────▼──────────────────┐ ┌────────────────▼─────────────┐
│ ReactAndroid │ │ React (iOS) │
│ ┌──────────────────────┐ │ │ ┌───────────────────────┐ │
│ │ Java/Kotlin Modules │ │ │ │ Obj-C/Swift Modules │ │
│ │ core (33K) │ │ │ │ Fabric/ │ │
│ │ uimanager (37K, 24f) │ │ │ │ Fabric/Utils/ (10f) │ │
│ │ turbomodule (25K) │ │ │ │ Base/ │ │
│ │ fabric events (5.4K) │ │ │ │ Profiler/ │ │
│ │ defaults (25K) │ │ │ │ Runtime/ │ │
│ │ permissions (7.5K) │ │ │ └───────────────────────┘ │
│ │ common (17K) │ │ │ │
│ │ devsupport (9.1K) │ │ │ CocoaPods / Swift PM │
│ └──────────────────────┘ │ │ Package.swift (40+ targets) │
│ │ │ │
│ Gradle Plugin (Kotlin) │ │ podspec files │
│ com.facebook.react │ │ │
│ com.facebook.react.root │ │ │
└────────────────────────────┘ └──────────────────────────────┘
1.2 Monorepo Structure
The repository is organized as a Yarn workspace monorepo. All published packages live under packages/, internal tooling under private/, and build/release automation under scripts/.
facebook/react-native/ (root — workspace config, CI)
│
├── packages/
│ ├── react-native/ # Core framework (268K chars at root)
│ │ ├── Libraries/ # JS framework code
│ │ │ ├── Core/ # AppRegistry, NativeModules
│ │ │ ├── Components/ # View, Text, Image, ScrollView
│ │ │ ├── Network/ # fetch, XHR, WebSocket
│ │ │ ├── Lists/ # List rendering infra
│ │ │ ├── LogBox/ # Error/warning overlay
│ │ │ └── Settings/ # Native settings bridge
│ │ ├── ReactAndroid/ # Android native (Java/Kotlin)
│ │ │ ├── src/main/java/.../ # Module implementations
│ │ │ │ ├── core/ # Core runtime (33K chars)
│ │ │ │ ├── permissions/ # Permission handling (7.5K)
│ │ │ │ ├── uimanager/ # UI events (37K, 24 files)
│ │ │ │ ├── fabric/ # Fabric events (5.4K)
│ │ │ │ ├── turbomodule/ # TurboModule core (25K)
│ │ │ │ ├── defaults/ # Default modules (25K)
│ │ │ │ ├── common/ # Shared utilities (17K)
│ │ │ │ ├── config/ # Config constants (842)
│ │ │ │ └── interfaces/ # Core interfaces (2.4K)
│ │ │ └── api/ # Public API surface definition
│ │ ├── ReactCommon/ # Shared C++ code
│ │ │ ├── react/renderer/ # Fabric renderer
│ │ │ │ ├── core/ # 82 files, 240K chars
│ │ │ │ ├── scheduler/ # 9 files, 32K chars
│ │ │ │ ├── animated/ # 7K chars
│ │ │ │ └── observers/events/ # 11K chars
│ │ │ ├── yoga/ # Yoga layout engine
│ │ │ │ ├── config/ # 5.4K chars
│ │ │ │ └── event/ # 4.9K chars
│ │ │ ├── jsi/ # JavaScript Interface
│ │ │ ├── hermes/ # Hermes engine integration
│ │ │ ├── jsinspector/ # Inspector protocol
│ │ │ └── nativemodule/ # TurboModule C++ infra
│ │ ├── ReactCxxPlatform/ # Cross-platform C++ impl
│ │ ├── React/ # iOS native (Obj-C/Swift)
│ │ │ ├── Fabric/ # Fabric renderer iOS
│ │ │ │ └── Utils/ # 10 files, 9.2K chars
│ │ │ ├── Base/ # Core iOS runtime
│ │ │ ├── Profiler/ # Performance profiling
│ │ │ └── Runtime/ # JS runtime integration
│ │ ├── src/private/ # Private JS APIs
│ │ │ ├── renderer/ # Private renderer
│ │ │ └── webapis/ # DOM events, XHR, etc.
│ │ ├── sdks/hermes-engine/ # Hermes utilities
│ │ ├── scripts/ # Codegen, feature flags, CocoaPods
│ │ └── Package.swift # SPM definition (40+ targets)
│ │
│ ├── community-cli-plugin/ # CLI: start, bundle
│ ├── metro-config/ # Metro bundler config
│ ├── dev-middleware/ # Dev server + inspector proxy
│ ├── debugger-frontend/ # Chrome DevTools debugger
│ ├── debugger-shell/ # Electron debugger shell
│ ├── babel-preset/ # Babel preset
│ ├── babel-plugin-codegen/ # Native codegen Babel plugin
│ ├── codegen/ # Code gen (Flow/TS → native)
│ ├── eslint-config/ # ESLint configuration
│ ├── eslint-plugin/ # ESLint plugin
│ ├── jest-preset/ # Jest test preset
│ ├── assets-registry/ # Asset registration system
│ ├── normalize-color/ # Color normalization (13.5K)
│ ├── virtualized-lists/ # FlatList, SectionList
│ ├── new-app-screen/ # Default new app screen
│ ├── typescript-config/ # TypeScript configuration
│ ├── polyfills/ # JS polyfills (24.4K)
│ ├── core-cli-utils/ # Core CLI utilities
│ └── gradle-plugin/ # Android Gradle plugin (Kotlin)
│ ├── src/ # Plugin source
│ │ └── main/kotlin/ # ReactPlugin, ReactRootProjectPlugin
│ │ └── utils/ # 48K chars utilities
│ └── src/test/ # 60K chars Kotlin tests
│
├── private/
│ ├── helloworld/ # Reference test app
│ ├── react-native-fantom/ # Internal test framework
│ │ ├── runner/ # Test runner
│ │ ├── tester/ # Assertion utilities
│ │ └── benchmarking/ # Performance measurement
│ └── eslint-plugin-monorepo/ # Monorepo ESLint rules
│
├── scripts/
│ ├── releases/ # Release automation
│ │ ├── npm publish workflows
│ │ ├── version management
│ │ ├── iOS prebuild
│ │ └── DotSlash distribution
│ ├── cxx-api/parser/ # C++ API snapshot (Python, 86K)
│ ├── js-api/ # JS API type gen/diffing
│ ├── release-testing/ # Release test utilities
│ ├── e2e/ # E2E test utilities
│ └── shared/ # Shared utilities
│
└── yarn.lock # Pinned dependencies
1.3 Rendering Pipeline: Fabric
Fabric is the current rendering architecture, replacing the legacy UIManager. It operates through a C++ core shared across platforms with platform-specific mounting implementations.
React Component Tree (JavaScript)
│
│ React.createElement() / JSX
▼
React Reconciler
│ Diffs current vs. previous virtual tree
│ Produces list of mutations
▼
Shadow Tree (C++ — ReactCommon/react/renderer/core/)
│ ShadowNode hierarchy mirrors component tree
│ Each node: Props + State + EventEmitter
│ ComponentDescriptor registry maps type → node factory
▼
Yoga Layout Engine (C++ — ReactCommon/yoga/)
│ Processes Flexbox styles
│ Computes absolute position + size for each node
│ Config: ReactCommon/yoga/yoga/config/ (5.4K chars)
│ Events: ReactCommon/yoga/yoga/event/ (4.9K chars)
▼
Scheduler (C++ — ReactCommon/react/renderer/scheduler/)
│ 9 files, 32K chars
│ Coordinates mutations across JS thread and main/UI thread
│ Batches updates for efficiency
▼
Mounting Layer (platform-specific)
├── Android: ReactAndroid/fabric/
│ └── Java/Kotlin code creates/updates/deletes Android Views
└── iOS: React/Fabric/
└── Obj-C/Swift code creates/updates/deletes UIKit Views
└── Utils/: 10 files, 9.2K chars
│
▼
Native Platform Views (rendered on screen)
Fabric renderer core (ReactCommon/react/renderer/):
| Subsystem | Location | Files | Size | Key Classes |
|---|---|---|---|---|
| Core | core/ |
82 | 240K chars | ShadowNode, Props, State, EventEmitter, ComponentDescriptor |
| Scheduler | scheduler/ |
9 | 32K chars | Thread coordination, mutation batching |
| Animated | animated/ |
— | 7K chars | Native animation driver |
| Events/Observers | observers/events/ |
— | 11K chars | Event dispatch and observation system |
Important
Fabric operates synchronously via JSI, meaning layout calculations and view updates can happen on the same frame as the JS render call. This is a fundamental departure from the old async bridge architecture, where messages were serialized, batched, and sent across threads with at least one frame of latency.
1.4 JavaScript Interface (JSI)
JSI is the C++ abstraction layer that allows JavaScript code to call native functions synchronously without serialization. It replaces the old asynchronous bridge entirely.
Key properties:
| Property | Description |
|---|---|
| Engine-agnostic | Works with Hermes, JavaScriptCore, or V8 |
| Synchronous | Native calls from JS execute on the calling thread without queuing |
| No serialization | Objects passed by reference via HostObject, not JSON-encoded |
| Location | ReactCommon/jsi/ with Hermes adapter in ReactCommon/hermes/ |
JSI concepts:
- HostObject — a C++ object exposed to JavaScript. JS code can get/set properties and call methods on it, with each operation forwarding to C++ synchronously.
- HostFunction — a C++ function callable from JavaScript. Receives JS arguments, returns JS values, executes synchronously.
- Runtime — the abstract interface to a JavaScript engine. Hermes, JSC, and V8 each provide a
Runtimeimplementation.
1.5 TurboModules
TurboModules replace the old Native Module system with codegen-driven, type-safe bindings that leverage JSI for synchronous access.
JS Spec File (Flow or TypeScript)
│ e.g., NativeDeviceInfo.js
│ Declares: interface extends TurboModule { ... }
▼
@react-native/codegen
│ Parses spec via Flow Parser or TypeScript Parser
│ Validates types, extracts method signatures
▼
Generated Native Bindings
├── C++ header + implementation
│ (type-safe JSI HostObject wrapper)
├── Java/Kotlin (Android)
│ ReactAndroid/.../turbomodule/core/ (25K chars)
│ ReactAndroid/.../internal/turbomodule/core/ (25K chars)
└── Objective-C (iOS)
(JSI direct invocation)
TurboModule characteristics:
| Feature | Description |
|---|---|
| Lazy initialization | Modules loaded on first access, not at startup |
| Synchronous calls | Methods invoked synchronously via JSI, no async bridge |
| Type safety | Codegen validates JS spec types match native implementation |
| Bidirectional | Native can call back into JS; JS can call native |
1.6 Yoga Layout Engine
Yoga is a cross-platform C++ implementation of the CSS Flexbox specification. It is used by React Native on all platforms to compute the position and size of every view in the tree.
Yoga architecture:
| Component | Location | Size | Purpose |
|---|---|---|---|
| Config | ReactCommon/yoga/yoga/config/ |
5.4K chars | Layout behavior settings, experimental features |
| Events | ReactCommon/yoga/yoga/event/ |
4.9K chars | Layout event callbacks for profiling/debugging |
| Core | ReactCommon/yoga/yoga/ |
— | Node, Style, Value types; layout algorithm |
Yoga is compiled as a standalone static library. It is also consumed independently by other Meta projects including Litho (Android) and ComponentKit (iOS).
1.7 ReactCxxPlatform
The ReactCxxPlatform/ directory contains a cross-platform C++ implementation layer that provides platform-agnostic abstractions consumed by both Android and iOS. This layer sits between the shared ReactCommon/ code and the platform-specific ReactAndroid/ and React/ directories.
1.8 Hermes Engine
Hermes is Meta's JavaScript engine purpose-built for React Native. It integrates at multiple levels:
Build Time:
JavaScript Source Code
│
▼ Hermes Compiler (hermesc)
Hermes Bytecode (.hbc)
│
▼ Bundled into APK/IPA
Runtime:
ReactCommon/hermes/
│ JSI adapter
▼
Hermes Virtual Machine
│ Executes .hbc directly (no parse step)
▼
Application running
Key advantages over JavaScriptCore:
- Bytecode precompilation eliminates JS parsing at startup
- Lower memory footprint on mobile devices
- Faster time-to-interactive
- SDK utilities in
sdks/hermes-engine/
2. System Requirements
2.1 Host Machine Requirements
| Component | Requirement | Notes |
|---|---|---|
| Node.js | ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 |
Required for Metro bundler, CLI, and all JS tooling |
| Yarn | 1.22.22 | Workspace monorepo package manager |
| JDK | 17 | Gradle toolchain requirement; JVM 11 bytecode target |
| Ruby | >= 2.6.10 | Required for CocoaPods on iOS |
2.2 Android Build Requirements
| Component | Requirement | How to Configure |
|---|---|---|
| Android SDK | Latest stable | Set ANDROID_HOME environment variable |
| Android Gradle Plugin (AGP) | Compatible version | Managed by packages/gradle-plugin |
| Kotlin Gradle Plugin (KGP) | Compatible version | Managed by packages/gradle-plugin |
| Gradle | Project-bundled wrapper | Use ./gradlew (see Gradle 9.0.0 caveat below) |
| NDK | Required for C++ compilation | Configured via Gradle plugin |
| CMake | Required for native builds | Configured via Gradle plugin |
Warning
The foojay-resolver-convention plugin at version 0.5.0 is incompatible with Gradle 9.0.0 (issue #56287). If upgrading Gradle, verify the foojay plugin version is compatible before proceeding. This affects the JDK toolchain auto-provisioning functionality.
2.3 iOS Build Requirements
| Component | Requirement | Notes |
|---|---|---|
| macOS | Required | iOS builds only possible on macOS |
| Xcode | Latest stable recommended | Includes Apple toolchains, simulators |
| CocoaPods | For Podfile-based projects | gem install cocoapods |
| Swift Package Manager | For SPM-based projects | Bundled with Xcode |
2.4 Key Development Dependencies
| Package | Version | Purpose | Required For |
|---|---|---|---|
@babel/core |
^7.25.2 | JavaScript transpilation | All platforms |
react |
19.2.3 | React core library | All platforms |
typescript |
5.8.3 | TypeScript compiler | TypeScript projects, codegen |
jest |
^29.7.0 | Test runner | Testing |
flow-bin |
^0.309.0 | Flow type checker | Core development |
prettier |
3.6.2 | Code formatter | Core development |
Note
The JDK version requirement is specifically 17 for the Gradle toolchain, even though the compiled bytecode targets JVM 11. Ensure your
JAVA_HOMEpoints to a JDK 17 installation when building Android. Using JDK 11 or JDK 21 for compilation will fail.
2.5 Version Compatibility Matrix
| React Native | React | Node.js | Hermes | Gradle Plugin |
|---|---|---|---|---|
| 0.86.0-main | 19.2.3 | ^20.19.4 / ^22.13.0 / ^24.3.0 / >=25 | Bundled | com.facebook.react |
3. Configuration Reference
3.1 Environment Variables
Complete reference of all environment variables identified in the source:
| Variable | Default | Scope | Description |
|---|---|---|---|
ANDROID_HOME |
(none) | Android builds | Path to Android SDK installation directory. Must be set before any Android build. Typically ~/Android/Sdk on Linux, ~/Library/Android/sdk on macOS. |
RCT_METRO_PORT |
8081 |
Development | Port for the Metro development server. Set this to avoid port conflicts when running multiple projects. |
NODE_ENV |
(none) | Runtime | Node environment mode. Values: development (enables dev tools, LogBox, inspector), production (strips dev code, enables optimizations), test (test mode). |
REACT_NATIVE_DEBUGGER_FRONTEND_PATH |
(none) | Development | Absolute path to a custom debugger frontend build. When set, overrides the bundled @react-native/debugger-frontend package. |
npm_lifecycle_event |
(set by npm) | Internal | Current npm script lifecycle event. Used by internal tooling to detect which script phase is running. |
npm_config_registry |
(npm default) | Publishing | npm registry URL. Used by release scripts when publishing packages. |
SKIP |
(none) | CLI | When set, skips certain CLI operations. Used as a boolean flag. |
DEBUG |
(none) | Development | Enables verbose debug logging in Metro configuration and middleware. |
FANTOM_* |
(various) | Testing | Family of prefixed variables for the internal Fantom test framework configuration. |
3.2 Metro Bundler Configuration
The @react-native/metro-config package provides getDefaultConfig(projectRoot) which returns the canonical Metro configuration object.
3.2.1 Basic Usage
// metro.config.js — typical project configuration
const { getDefaultConfig } = require('@react-native/metro-config');
const config = getDefaultConfig(__dirname);
module.exports = config;
3.2.2 Default Configuration Values
Resolver Configuration:
| Key | Default Value | Description |
|---|---|---|
resolverMainFields |
['react-native', 'browser', 'main'] |
Package.json fields checked in order for module resolution. The react-native field takes priority, enabling platform-specific module overrides. |
platforms |
['android', 'ios'] |
Supported platforms. Metro uses these to resolve .android.js and .ios.js platform extensions. |
Serializer Configuration:
| Key | Default Value | Description |
|---|---|---|
| Module init order | InitializeCore first, then polyfills |
The InitializeCore module is always the first to execute, bootstrapping the React Native runtime before any polyfills or application code. |
Server Configuration:
| Key | Default Value | Description |
|---|---|---|
port |
8081 |
HTTP port for the Metro dev server. Override with RCT_METRO_PORT env var or this config key. |
Transformer Configuration:
| Key | Default Value | Description |
|---|---|---|
| Babel transformer | @react-native/metro-babel-transformer |
The Babel transformer used to transpile JavaScript/TypeScript/Flow source files. |
inlineRequires |
true |
Defers module initialization until require() is called. Improves startup time by not executing module code until needed. |
Tip
When customizing Metro configuration, always spread the defaults from
getDefaultConfig()first and override individual keys. The resolver field order (react-nativebeforebrowserbeforemain) is critical for correct platform-specific module resolution. Changing this order can cause the wrong module variant to be bundled.
3.2.3 Advanced Configuration Patterns
// metro.config.js — extending defaults
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const defaultConfig = getDefaultConfig(__dirname);
const customConfig = {
resolver: {
// Add additional platforms
platforms: [...defaultConfig.resolver.platforms, 'web'],
},
server: {
// Custom port
port: 8088,
},
};
module.exports = mergeConfig(defaultConfig, customConfig);
3.3 Gradle Plugin Configuration
The React Native Gradle Plugin provides two plugin IDs applied at different project levels:
| Plugin ID | Applied To | Class | Purpose |
|---|---|---|---|
com.facebook.react |
App/library modules | ReactPlugin |
Configures React Native build for individual Android modules |
com.facebook.react.rootproject |
Root build.gradle |
ReactRootProjectPlugin |
Project-wide configuration, dependency alignment |
Plugin implementation details:
| Aspect | Detail |
|---|---|
| Language | Kotlin |
| JDK toolchain | 17 (compilation) |
| JVM target | 11 (runtime compatibility) |
| Dependencies | AGP, KGP, Gson, Guava, JavaPoet |
| Utils module | 48K chars — build configuration, dependency management, task registration |
| Test suite | 60K chars — comprehensive Kotlin tests |
What the plugin configures:
- Codegen tasks — generates native bindings from JS spec files
- Hermes compilation — compiles JS to Hermes bytecode for release builds
- Native library compilation — configures CMake/ndk-build for C++ code
- Dependency management — aligns React Native library versions
- Build variants — configures debug/release build differences
3.4 Babel Configuration
The @react-native/babel-preset provides the standard Babel configuration for React Native projects. It includes transforms for:
- JSX syntax
- Flow type annotations (stripping)
- TypeScript support
- React Native-specific optimizations
- Module system compatibility
The companion @react-native/babel-plugin-codegen integrates native module code generation into the Babel transform pipeline. During bundling, it detects spec files (files matching Native*.js patterns with TurboModule interfaces) and triggers codegen automatically.
3.5 Swift Package Manager Targets
Package.swift defines 40+ build targets for iOS. These targets mirror the CocoaPods pod structure but use SPM's native dependency resolution.
| Target Category | Target Names | Description |
|---|---|---|
| Layout | yoga |
Yoga Flexbox layout engine |
| JS Interface | jsi |
JavaScript Interface abstraction |
| Utilities | reactUtils |
Shared React Native utilities |
| Feature Flags | reactFeatureFlags |
Compile-time feature flag system |
| Rendering | reactFabric, reactGraphics |
Fabric renderer and graphics primitives |
| Runtime | reactHermes, reactCxxReact |
Hermes integration, C++ React core |
| Modules | Various TurboModule targets | Platform-specific native module implementations |
Note
Swift Package Manager support via
Package.swiftis an alternative to CocoaPods. Both package managers can resolve the same source code, but they cannot be mixed in the same project. Choose one approach and use it consistently.
3.6 ESLint Configuration
Two ESLint packages provide linting rules:
| Package | Scope | Description |
|---|---|---|
@react-native/eslint-config |
Consumer projects | Standard ESLint configuration for React Native apps |
@react-native/eslint-plugin |
Consumer projects | Custom ESLint rules for React Native patterns |
private/eslint-plugin-monorepo |
Internal only | Monorepo-specific rules (import boundaries, workspace consistency) |
3.7 TypeScript Configuration
The @react-native/typescript-config package provides a base tsconfig.json that React Native projects can extend. It configures:
- Target and module settings compatible with Metro's module resolution
- JSX support for React Native
- Path aliases and type roots
- Strict mode settings
4. Deployment & Scaling
4.1 CLI Commands
The @react-native/community-cli-plugin provides two primary commands. It depends on: metro, dev-middleware, debug, semver.
4.1.1 start — Development Server
Launches the Metro development server, which provides:
| Capability | Description |
|---|---|
| JavaScript bundling | Compiles and serves JS bundles on-demand for connected devices |
| Hot Module Replacement | Pushes code changes to running apps without full reload |
| Inspector proxy | Multiplexes Chrome DevTools Protocol sessions (see Section 5.1) |
| Source map serving | Generates and serves source maps for debugging |
| Asset serving | Resolves and serves static assets (images, fonts) |
| Debugger launcher | Opens React Native DevTools when requested |
Port configuration precedence:
- Command-line
--portflag (highest priority) RCT_METRO_PORTenvironment variableserver.portinmetro.config.js- Default:
8081
4.1.2 bundle — Production Bundle
Creates an optimized JavaScript bundle for deployment to devices.
Bundle process:
- Resolves all module dependencies starting from the entry point
- Applies Babel transforms (including codegen for TurboModule specs)
- Tree-shakes unused code (in production mode)
- Concatenates modules into a single file
- Generates source map (optional)
- Outputs platform-specific bundle (
.android.jsor.ios.jsextensions resolved)
4.2 Android Build Pipeline
4.2.1 Build Flow
Project Source
│
├── JavaScript/TypeScript/Flow
│ │
│ ▼ @react-native/codegen
│ Generated Java/C++ bindings
│
├── Java/Kotlin Source
│ │
│ ▼ Gradle (javac/kotlinc, JDK 17 toolchain → JVM 11 target)
│ .class files
│
├── C++ Source (ReactCommon + ReactAndroid native)
│ │
│ ▼ CMake / ndk-build (NDK)
│ .so shared libraries
│
└── JavaScript Bundle
│
▼ Hermes Compiler (release builds)
.hbc bytecode
│
▼ Gradle assembleRelease / assembleDebug
APK or AAB
4.2.2 ReactAndroid Module Inventory
Complete inventory of the Android native layer:
| Module | Size | Files | Description |
|---|---|---|---|
| core | 33K chars | — | Core React Native Android runtime: ReactContext, ReactInstanceManager, bridge lifecycle |
| uimanager events | 37K chars | 24 | Touch, scroll, focus, text input, and other UI event handling |
| turbomodule core | 25K chars | — | TurboModule infrastructure: module registry, JSI bindings, method invocation |
| defaults | 25K chars | — | Default module implementations shipped with React Native |
| common | 17K chars | — | Shared Android utilities: threading, logging, system info |
| devsupport interfaces | 9.1K chars | 12 | Development support API: dev menu, reload, inspector connection |
| permissions | 7.5K chars | — | Android runtime permission request/grant handling |
| fabric events | 5.4K chars | — | Fabric renderer event dispatch for Android |
| common annotations | 4.8K chars | — | Internal annotation types (@ReactModule, @ReactProp, etc.) |
| interfaces | 2.4K chars | — | Core interface definitions (ReactContext, JSModule, etc.) |
| views common | 2.1K chars | — | Shared view component utilities |
| config | 842 chars | — | Configuration constants and defaults |
4.2.3 Gradle Plugin Behavior
The com.facebook.react Gradle plugin automates the following during Android builds:
- Codegen phase — scans for JS spec files, generates native bindings
- Bundle phase — invokes Metro to create the JS bundle (release builds)
- Hermes phase — compiles JS bundle to Hermes bytecode (when Hermes enabled)
- Native build — configures CMake for C++ compilation with correct includes
- Packaging — bundles .so libraries, assets, and bytecode into APK/AAB
4.3 iOS Build Pipeline
4.3.1 Build Flow
Project Source
│
├── JavaScript/TypeScript/Flow
│ │
│ ▼ @react-native/codegen
│ Generated Obj-C/C++ bindings
│
├── Objective-C / Swift Source
│ │
│ ▼ Xcode build system (clang/swiftc)
│ .o object files
│
├── C++ Source (ReactCommon + React/ native)
│ │
│ ▼ Xcode build system (clang++)
│ .o object files
│
└── JavaScript Bundle
│
▼ Hermes Compiler (release builds)
.hbc bytecode
│
▼ Xcode archive / build
.app or .ipa
4.3.2 iOS Native Code Organization
| Directory | Contents | Size |
|---|---|---|
React/Fabric/ |
Fabric renderer iOS implementation | — |
React/Fabric/Utils/ |
Fabric utilities (view conversion, prop handling) | 10 files, 9.2K chars |
React/Base/ |
Core iOS runtime (RCTBridge, RCTRootView) | — |
React/Profiler/ |
Performance profiling hooks for Instruments | — |
React/Runtime/ |
JS runtime integration (Hermes/JSC setup) | — |
4.3.3 CocoaPods Integration
CocoaPods is the traditional dependency manager for iOS React Native projects.
Key files:
- Podspec files in
packages/react-native/define pod dependencies scripts/contains CocoaPods utility scripts and iOS prebuild helpers- Hermes engine utilities in
sdks/hermes-engine/
Pod structure maps to the codebase:
React-Core— Core runtimeReact-Fabric— Fabric rendererReact-Hermes— Hermes engine integrationYoga— Layout engine- 40+ additional subspecs for individual modules
Caution
Inconsistent
Podfile.lockchecksums forhermes-enginehave been reported (issue #54891). When experiencing checksum mismatches, clean the Pods cache completely (pod cache clean hermes-engine --all) and regenerate the lock file (pod install --repo-update). Do not manually edit checksum values inPodfile.lock.
4.3.4 Swift Package Manager Integration
SPM is an alternative to CocoaPods, defined in Package.swift at the package root.
Advantages over CocoaPods:
- No Ruby dependency
- Integrated with Xcode (no
pod installstep) - Faster dependency resolution
- Better compile-time caching
Current status: Package.swift defines 40+ targets covering yoga, JSI, Fabric, Hermes, and utility modules.
4.4 Code Generation Pipeline
The @react-native/codegen package is central to both platform build pipelines.
4.4.1 Codegen Architecture
Spec Files
│
│ NativeModule spec: interface TurboModule { ... }
│ Component spec: codegenNativeComponent(...)
│
▼
@react-native/codegen
│
├── Flow Parser
│ │ Parses Flow-typed spec files
│ │ Extracts type information, method signatures
│ ▼
│ Intermediate Representation (IR)
│
├── TypeScript Parser
│ │ Parses TS-typed spec files
│ │ Extracts type information, method signatures
│ ▼
│ Intermediate Representation (IR)
│
▼
Code Generators (per-platform)
│
├── C++ Generator
│ └── Headers + implementations for JSI bindings
│
├── Java Generator
│ └── Java interfaces and abstract classes for Android
│
└── Objective-C Generator
└── ObjC protocols and method stubs for iOS
4.4.2 Babel Integration
The @react-native/babel-plugin-codegen integrates codegen into the Babel transform pipeline. This means codegen runs automatically during Metro bundling — no separate build step required for the JS side.
How it works:
- Babel processes each JS file through the transform pipeline
- The codegen plugin detects spec files (by convention:
Native*.jswith TurboModule interface) - On detection, it triggers the codegen pipeline for that spec
- Generated native code is placed alongside the spec file (or in a configured output directory)
5. Operations
5.1 Development Server Operations
5.1.1 Metro Dev Server
The Metro development server (default port 8081) is the central hub during development. It runs as a long-lived process that serves JavaScript bundles, handles Hot Module Replacement, and hosts the inspector proxy.
Lifecycle:
- Server starts, loads
metro.config.js - Watches filesystem for source changes
- Devices connect and request bundles
- On file change: invalidates affected modules, pushes updates via HMR
- Inspector proxy runs in-process, manages debug sessions
Server port configuration precedence:
- CLI
--portflag RCT_METRO_PORTenvironment variablemetro.config.js→server.port- Default:
8081
5.1.2 Inspector Proxy Protocol
The dev-middleware package provides an inspector proxy that multiplexes Chrome DevTools Protocol (CDP) sessions between devices and debuggers. This is the core debugging infrastructure for React Native.
HTTP endpoints:
| Method | Endpoint | Response | Description |
|---|---|---|---|
| GET | /json |
JSON array | List available debug targets (pages) |
| GET | /json/list |
JSON array | Same as /json — alias for compatibility |
| GET | /json/version |
JSON object | Inspector proxy version information |
WebSocket endpoints:
| Endpoint | Direction | Description |
|---|---|---|
/inspector/device?device={id}&name={name}&app={bundle_id} |
Device → Proxy | Device registers itself with the proxy, providing device ID, name, and app bundle identifier |
/inspector/debug?device={device_id}&page={page_id} |
Debugger → Proxy | Debugger connects to a specific page on a specific device |
Inspector protocol messages:
| Event | Direction | Payload | Description |
|---|---|---|---|
getPages |
Proxy → Device | — | Request list of debuggable pages |
connect |
Proxy → Device | page ID | Establish debug session for a page |
disconnect |
Proxy → Device | page ID | Terminate debug session |
wrappedEvent |
Bidirectional | CDP payload | Forward CDP messages between debugger and device |
Page capabilities (reported per-page by the device):
| Capability | Type | Description |
|---|---|---|
nativePageReloads |
boolean | Page supports native-triggered reloads |
nativeSourceCodeFetching |
boolean | Page supports fetching source from device storage |
supportsMultipleDebuggers |
boolean | Multiple debuggers can connect to this page simultaneously |
WebSocket close reason codes:
| Code | Meaning | Typical Trigger |
|---|---|---|
PAGE_NOT_FOUND |
Target page no longer exists | Page navigated away or component unmounted |
CONNECTION_LOST |
Network connection dropped | WiFi disconnect, USB unplug |
RECREATING_DEVICE |
Device re-registering with proxy | App restart, background/foreground cycle |
NEW_DEBUGGER_OPENED |
Another debugger took over session | User opened a second DevTools window |
UNREGISTERED_DEVICE |
Device disconnected from proxy | App killed, device disconnected |
INCORRECT_URL |
Malformed WebSocket URL | Client programming error |
Legacy features:
- Synthetic Reloadable Page (ID
-1): a virtual page that exists for backward compatibility with older debugger clients. Selecting it triggers a full app reload. - URL rewriting: the proxy rewrites source map URLs to ensure debuggers can fetch sources correctly regardless of network topology (e.g., when proxy is on a different host than the device).
Note
The inspector proxy multiplexes all debug connections through a single WebSocket per device. When a device registers at
/inspector/device, it maintains one persistent WebSocket. All debugger connections for that device's pages are multiplexed over this single connection using thewrappedEventprotocol.
5.2 Debugger Infrastructure
The debugging toolchain consists of three packages working together in a layered architecture:
User Interface Layer:
┌─────────────────────────────────────────────┐
│ @react-native/debugger-frontend │
│ Chrome DevTools-based UI │
│ (Sources, Console, Network, Profiler) │
└─────────────────────┬───────────────────────┘
│
Hosting Layer: │
┌─────────────────────▼───────────────────────┐
│ @react-native/debugger-shell │
│ Electron/Node shell ("React Native DevTools") │
│ Hosts the frontend, manages window │
└─────────────────────┬───────────────────────┘
│
Transport Layer: │ CDP over WebSocket
┌─────────────────────▼───────────────────────┐
│ @react-native/dev-middleware │
│ Inspector proxy + server middleware │
│ Multiplexes CDP sessions │
└─────────────────────┬───────────────────────┘
│ WebSocket
┌─────────────────────▼───────────────────────┐
│ Device (running app) │
│ jsinspector (ReactCommon/jsinspector/) │
│ Exposes Hermes/JSC debugger via CDP │
└─────────────────────────────────────────────┘
Custom debugger frontend:
Set the REACT_NATIVE_DEBUGGER_FRONTEND_PATH environment variable to point to a custom build of the debugger frontend. This is useful for teams that need to add custom panels or modify the DevTools UI.
5.3 Asset Management
The @react-native/assets-registry provides the runtime asset registration system.
API:
registerAsset(asset)— registers an asset (image, font, video, etc.) and returns a numeric IDgetAssetByID(id)— retrieves a registered asset by its numeric ID
Asset resolution flow:
- Metro's asset resolver finds assets during bundling (via file extension matching)
- Assets are processed (resized, hashed) and placed in the bundle output
- At runtime,
registerAsset()is called for each asset - Components reference assets by their registered ID
5.4 Polyfills and Runtime Initialization
The @react-native/polyfills package (24.4K chars) provides JavaScript polyfills that are injected before application code runs.
Initialization order (enforced by Metro serializer):
InitializeCore— bootstraps the React Native runtime environment- Polyfills from
@react-native/polyfills— fills gaps in the JS engine - Application entry point — the app's
index.jsor configured entry
This ordering is critical. InitializeCore sets up globals (like __DEV__, global, error handling) that polyfills and application code depend on.
5.5 Private Web API Implementations
The src/private/webapis/ directory contains implementations of standard Web APIs that are not natively available in React Native's JavaScript environment:
| Web API | Implementation | Description |
|---|---|---|
| DOM Events | src/private/webapis/dom/events/ |
W3C-compatible event dispatch, EventTarget |
| XMLHttpRequest | src/private/webapis/xhr/ |
XHR implementation backed by React Native's native networking module |
| MutationObserver | src/private/webapis/mutationobserver/ |
DOM mutation observation, adapted for Fabric's view tree |
| Geometry | src/private/webapis/geometry/ |
DOMRect, DOMPoint, and related measurement APIs |
| Microtasks | src/private/webapis/microtasks/ |
queueMicrotask implementation |
| Idle Callbacks | src/private/webapis/idle/ |
requestIdleCallback / cancelIdleCallback |
| Console | src/private/webapis/console/ |
Console API with native logging integration |
These APIs enable code that uses standard Web APIs to work within the React Native runtime without modification.
5.6 Release Process
Release automation lives in scripts/releases/ and covers the full release lifecycle:
| Phase | Scripts | Description |
|---|---|---|
| Version management | scripts/releases/ |
Bumps version numbers across all packages |
| npm publish | scripts/releases/ |
Publishes packages to npm registry |
| iOS prebuild | scripts/releases/ |
Pre-builds iOS frameworks for faster consumer builds |
| DotSlash | scripts/releases/ |
Binary distribution via DotSlash |
API surface tracking for releases:
| Tool | Location | Size | Method |
|---|---|---|---|
| JavaScript API tracker | scripts/js-api/ |
— | Generates TypeScript type definitions, diffs between versions |
| C++ API tracker | scripts/cxx-api/parser/ |
86K chars | Doxygen-based parser (Python), creates API snapshots for comparison |
| Android API surface | ReactAndroid/api/ |
— | Defined API surface files tracked in version control |
5.7 Virtualized Lists
The @react-native/virtualized-lists package contains the core list virtualization logic used by FlatList and SectionList. It is extracted as a separate package for independent versioning and testing.
Key responsibilities:
- Window calculation (which items are visible)
- Cell recycling and off-screen cleanup
- Scroll position management
- On-demand rendering as user scrolls
- Section header stickiness (SectionList)
5.8 Color Normalization
The @react-native/normalize-color package (13.5K chars) converts color values from various formats to a normalized 32-bit integer representation consumed by native views:
Supported input formats:
- Named colors (CSS color names)
- Hex:
#RGB,#RRGGBB,#RRGGBBAA rgb(r, g, b),rgba(r, g, b, a)hsl(h, s%, l%),hsla(h, s%, l%, a)
6. Performance
6.1 Architectural Performance Characteristics
6.1.1 JSI Synchronous Calls
The JSI layer eliminates the serialization overhead of the old bridge. In the legacy architecture, every native call required:
- Serialize JS arguments to JSON
- Queue the message on the bridge
- Deserialize on the native side
- Execute
- Serialize the return value
- Queue the response
- Deserialize in JS
With JSI, native calls from JavaScript execute synchronously on the calling thread. The JS engine directly invokes C++ functions, passing values by reference. This reduces per-call latency from milliseconds (bridge serialization + async queue) to microseconds (direct function call).
6.1.2 TurboModule Lazy Loading
TurboModules are initialized on first access rather than at startup. In the legacy architecture, all Native Modules were initialized eagerly during app launch, contributing to slow startup times — especially for apps with many modules.
Impact on startup:
- Only modules actually used in the initial render are loaded
- Rarely-used modules (e.g., camera, Bluetooth) are deferred until invoked
- Reduces startup module initialization from "all N modules" to "only the ~5-10 needed for first screen"
6.1.3 Fabric Renderer Performance
Fabric's C++ core eliminates several bottlenecks of the old renderer:
| Aspect | Legacy (UIManager) | Fabric |
|---|---|---|
| Layout | JS-side, then sent to native | C++ (Yoga), same thread as render |
| Mutations | Async, batched across bridge | Synchronous via JSI |
| Shadow tree | Maintained in JS | Maintained in C++ |
| Threading | Multi-hop across bridge | Direct scheduler coordination |
6.1.4 Yoga Layout Performance
Yoga computes Flexbox layouts in optimized C++ code. Key performance characteristics:
- Layout calculations run on the native thread, not the JS thread
- Incremental layout: only recalculates affected subtrees when props change
- No JS↔native round-trip for layout — it happens entirely in C++
6.2 Metro Bundler Optimization
| Setting | Default | Effect |
|---|---|---|
inlineRequires |
true |
Defers module initialization until first require() call. Each module's factory function is wrapped; it only executes when first imported. Reduces startup cost of large dependency trees. |
| Resolver field order | ['react-native', 'browser', 'main'] |
Ensures platform-optimized modules are resolved first. Many libraries ship lighter React Native-specific bundles via the react-native field. |
| Serializer module ordering | InitializeCore first |
Ensures runtime is bootstrapped before polyfills and app code, avoiding undefined-global errors. |
| Tree shaking | Production mode | Dead code elimination in production bundles. |
6.3 Animation Architecture
The internal animated driver (ReactCommon/react/renderer/animated/, 7K chars) operates in two modes:
Native driver (recommended):
- Animation calculations run in C++ on the UI thread
- No JS thread involvement after animation is configured
- Achieves consistent 60fps even when JS thread is busy
- Suitable for: opacity, transform, layout animations
JS driver (fallback):
- Animation calculations run on the JS thread
- Each frame requires JS → native round-trip
- Can drop frames if JS thread is busy (long computations, network callbacks)
- Required when animation values drive non-native properties
6.4 Hermes Engine Performance
Hermes provides multiple performance advantages:
| Feature | Impact |
|---|---|
| Bytecode precompilation | Eliminates JS parsing at startup. The .hbc file is loaded and executed directly. |
| Smaller engine binary | Reduces APK/IPA size |
| Lower memory footprint | Optimized garbage collector for mobile constraints |
| Faster GC | Generational GC tuned for React Native's allocation patterns |
Tip
For production builds, Hermes bytecode precompilation is the single most impactful performance optimization. It eliminates JavaScript parsing time entirely at app startup, often saving hundreds of milliseconds on mid-range devices. Always verify Hermes is enabled in your production build configuration.
6.5 Benchmarking with Fantom
The internal react-native-fantom framework (private/react-native-fantom/) provides structured benchmarking alongside its test runner.
Components:
- Runner — discovers and executes benchmark definitions
- Tester — assertion and verification utilities
- Benchmarking — timing, statistical analysis, regression detection
Runtime constraints:
- Benchmarks must not run in development mode (error:
Benchmarks should not be run in development mode) - Benchmark tests must be explicitly defined (error:
No benchmark tests definedif none are found) - These constraints ensure meaningful, reproducible results
6.6 Startup Performance Optimization Checklist
| Optimization | Layer | Impact |
|---|---|---|
| Enable Hermes | Build | Eliminates JS parse time |
inlineRequires: true |
Metro | Defers module init |
| TurboModules (not legacy NativeModules) | Architecture | Lazy module loading |
| Minimize initial module count | Application | Fewer modules to init at startup |
| Use Fabric renderer | Architecture | Faster initial render |
| Optimize images (resolution, format) | Assets | Faster asset loading |
| Split bundles (RAM bundles) | Metro | Load code on demand |
7. Security
7.1 Development Server Security
The Metro development server and inspector proxy are designed exclusively for local development use. They provide no authentication, authorization, or encryption.
Inspector proxy attack surface:
| Endpoint | Risk | Description |
|---|---|---|
GET /json |
Information disclosure | Reveals running app details, debuggable pages |
GET /json/list |
Information disclosure | Same as above |
GET /json/version |
Information disclosure | Proxy version information |
WS /inspector/device |
Remote code execution | Allows registering as a device (impersonation) |
WS /inspector/debug |
Remote code execution | Allows sending arbitrary CDP commands to apps |
Caution
Never expose the Metro development server or inspector proxy to untrusted networks. These services provide unauthenticated access to inspect, debug, and modify running application instances. In production builds, the dev server is not bundled — but verify this in your build configuration. For development on shared networks, bind Metro to
localhostonly (not0.0.0.0).
7.2 Code Generation Security
The codegen pipeline (@react-native/codegen) generates native bindings from JavaScript specifications. The generated code runs with full native privileges on the device.
Security considerations:
| Concern | Detail |
|---|---|
| Spec file trust | Codegen inputs define the native API surface. A malicious spec file could expose dangerous native APIs to JS. Treat spec files with the same scrutiny as native code. |
| Generated code review | Generated C++/Java/ObjC runs with native privileges. While codegen produces type-safe code, the types themselves (from specs) define what's accessible. |
| Memory safety | JSI bindings have direct memory access. Type mismatches between JS and native can cause memory corruption. Codegen reduces but does not eliminate this risk. |
| Third-party modules | TurboModules from third-party packages run with full native privileges. Audit third-party module specs before inclusion. |
7.3 Native Module Security
TurboModules and native modules operate outside the JavaScript sandbox with full access to platform APIs.
Security-relevant Android modules:
| Module | Size | Security Concern |
|---|---|---|
| permissions | 7.5K chars | Controls runtime permission grants (camera, location, storage, contacts, etc.) |
| network | — | All HTTP/HTTPS requests from the app. Controls data exfiltration surface. |
| blob | — | Binary data handling with file system access. |
| websocket | — | Bidirectional network communication channels. Can bypass HTTP proxy configurations. |
| core | 33K chars | Core runtime with broad system access. |
7.4 Supply Chain Security
The monorepo's dependency tree:
| Category | Key Dependencies | Risk Level |
|---|---|---|
| Build | @babel/core, metro, gradle, AGP, KGP | High — compromised build tools can inject malicious code |
| Runtime | react, hermes-engine | Critical — runs in all apps |
| Tooling | jest, flow-bin, typescript, prettier, eslint | Low — dev-only, not shipped |
| Native (Gradle) | Gson, Guava, JavaPoet | Medium — compiled into Android app |
Mitigations:
yarn.lockpins exact dependency versions for reproducible builds- Verify lockfile integrity in CI (detect unexpected changes)
- Audit dependency updates before merging lockfile changes
- Use
yarn auditto check for known vulnerabilities
7.5 Hermes Bytecode Security
Hermes bytecode (.hbc) bundles are shipped inside APK/IPA files and are not encrypted or obfuscated beyond compilation to bytecode.
Implications:
.hbcfiles can be extracted from APK (unzip) or IPA (decrypted on jailbroken device)- Hermes bytecode can be decompiled to readable JavaScript using available tools
- Business logic in JavaScript should not be considered secret
- API keys, tokens, and secrets must not be embedded in JavaScript code
- Use server-side validation for all security-critical logic
7.6 Network Security
React Native's networking stack (Libraries/Network/) uses platform-native HTTP clients:
- Android: OkHttp (respects system proxy, certificate pinning configurable)
- iOS: NSURLSession (respects system proxy, App Transport Security enforced by default)
Warning
WebSocket connections (
Libraries/WebSocket/) may bypass HTTP proxy configurations on some platforms. If your security model relies on proxy-based inspection or filtering, test WebSocket traffic paths explicitly.
8. Developer Internals
8.1 Core Package Deep Dive: packages/react-native
The core react-native package (268K chars at root level, much more including subdirectories) contains the complete framework implementation across four platform layers.
8.1.1 Libraries/ — JavaScript Framework Code
The Libraries/ directory is the JavaScript implementation of React Native's APIs. It contains everything that JS application code interacts with directly.
Subsystem inventory:
| Subsystem | Description | Key Exports |
|---|---|---|
| Core | Fundamental runtime | AppRegistry, NativeModules, NativeEventEmitter, Platform |
| Components | Built-in UI primitives | View, Text, Image, TextInput, ScrollView, FlatList, SectionList, TouchableOpacity, Pressable, Modal, StatusBar, ActivityIndicator, Switch, Button |
| Network | Networking APIs | fetch (polyfill), XMLHttpRequest, WebSocket |
| Lists | List rendering | Internal infrastructure consumed by @react-native/virtualized-lists |
| LogBox | Error display | Error and warning overlay shown in development |
| Settings | Persistent settings | Bridge to native settings (UserDefaults on iOS, SharedPreferences on Android) |
| Animated | Animation library | Animated.Value, Animated.timing, Animated.spring, Animated.decay |
| LayoutAnimation | Layout transitions | Automatic animation of layout changes |
| StyleSheet | Style system | StyleSheet.create, StyleSheet.flatten, style validation |
| Linking | Deep linking | URL scheme handling, universal links |
| Alert | Alerts | Native alert dialogs |
| Vibration | Haptics | Device vibration |
8.1.2 Private JS APIs (src/private/)
Internal JavaScript APIs not part of the public surface but essential to React Native's operation:
| Module | Location | Description | Used By |
|---|---|---|---|
| renderer | src/private/renderer/ |
Private renderer integration | Fabric rendering pipeline |
| DOM events | src/private/webapis/dom/events/ |
W3C-compatible event dispatch | Event system |
| XHR | src/private/webapis/xhr/ |
XMLHttpRequest implementation | fetch polyfill, user code |
| MutationObserver | src/private/webapis/mutationobserver/ |
DOM mutation observation | Fabric view tree tracking |
| Geometry | src/private/webapis/geometry/ |
DOMRect and related APIs | Layout measurement |
| Microtasks | src/private/webapis/microtasks/ |
queueMicrotask implementation |
Promise resolution, internals |
| Idle callbacks | src/private/webapis/idle/ |
requestIdleCallback / cancelIdleCallback |
Background task scheduling |
| Console | src/private/webapis/console/ |
Console API with native logging | All console.* calls |
Important
These private APIs are internal implementation details and not part of React Native's public API contract. They may change without notice between versions. Third-party code should not import from
src/private/directly.
8.1.3 ReactCommon/ — Shared C++ Core
This is the heart of React Native's cross-platform implementation. All code here is compiled for both Android (via NDK) and iOS (via Xcode).
Complete module inventory:
| Directory | Files | Size | Purpose | Key Types |
|---|---|---|---|---|
react/renderer/core/ |
82 | 240K chars | Fabric renderer core | ShadowNode, Props, State, EventEmitter, ComponentDescriptor |
react/renderer/scheduler/ |
9 | 32K chars | Thread coordination | Scheduler, SchedulerDelegate |
react/renderer/animated/ |
— | 7K chars | Native animation driver | AnimatedValue, AnimatedNode |
react/renderer/observers/events/ |
— | 11K chars | Event dispatch/observation | EventEmitter, EventDispatcher |
yoga/yoga/config/ |
— | 5.4K chars | Yoga layout config | YGConfig |
yoga/yoga/event/ |
— | 4.9K chars | Yoga layout events | YGEvent |
jsi/ |
— | — | JavaScript Interface | Runtime, Value, Object, Function, HostObject |
hermes/ |
— | — | Hermes JSI adapter | HermesRuntime |
jsinspector/ |
— | — | Inspector protocol | InspectorTarget, InspectorPage |
nativemodule/ |
— | — | TurboModule C++ infra | TurboModule, TurboModuleBinding |
Fabric renderer core classes (react/renderer/core/):
| Class | Purpose |
|---|---|
ShadowNode |
Represents a component in the shadow tree. Immutable. New instances created for each state change. |
Props |
Type-safe property container. Generated by codegen for each component type. |
State |
Mutable state associated with a shadow node. Updated via native thread. |
EventEmitter |
Dispatches events from native to JS. Each component has one. |
ComponentDescriptor |
Factory for creating ShadowNodes of a given component type. Registered globally. |
Scheduler (react/renderer/scheduler/):
The Scheduler coordinates operations across three threads:
- JS thread — where React reconciliation runs
- Background thread — where tree diffing and clone operations run
- Main/UI thread — where mounting (view creation/update/deletion) runs
8.1.4 ReactAndroid/ — Android Native Layer
Complete module breakdown:
| Module | Size | Files | Key Classes/Interfaces |
|---|---|---|---|
| core | 33K chars | — | ReactContext, ReactInstanceManager, ReactActivity, ReactApplication |
| uimanager events | 37K chars | 24 | Touch events, scroll events, focus events, text input events, selection events |
| turbomodule core | 25K chars | — | TurboModule, TurboModuleRegistry, ReactModuleInfo |
| defaults | 25K chars | — | Default module implementations (AsyncStorage, Clipboard, etc.) |
| common | 17K chars | — | ReactConstants, threading utilities, SystemClock, logging |
| devsupport interfaces | 9.1K chars | 12 | DevSupportManager, DevBundleDownloadListener, PackagerStatusCheck |
| permissions | 7.5K chars | — | PermissionsModule, PermissionAwareActivity |
| fabric events | 5.4K chars | — | Fabric-specific event dispatch for touch, scroll |
| common annotations | 4.8K chars | — | @ReactModule, @ReactProp, @ReactMethod and other internal annotations |
| interfaces | 2.4K chars | — | ReactContext, JSModule, LifecycleEventListener |
| views common | 2.1K chars | — | ViewProps, shared view utilities |
| config | 842 chars | — | Build configuration constants |
Android API surface is defined in ReactAndroid/api/ — these files are tracked in version control and changes are reviewed to prevent unintentional API breakage.
8.1.5 React/ — iOS Native Layer
| Directory | Contents | Key Classes |
|---|---|---|
Fabric/ |
Fabric renderer iOS | RCTFabricSurface, RCTMountingManager |
Fabric/Utils/ |
10 files, 9.2K chars | Prop conversion, view factory, image utils |
Base/ |
Core iOS runtime | RCTBridge, RCTRootView, RCTEventEmitter |
Profiler/ |
Performance profiling | Instruments integration, FPS monitor |
Runtime/ |
JS runtime integration | Hermes/JSC setup, runtime configuration |
8.2 Tooling Packages Reference
8.2.1 @react-native/community-cli-plugin
Purpose: Provides the start and bundle CLI commands.
Dependencies: metro, dev-middleware, debug, semver
Commands:
| Command | Description | Key Flags |
|---|---|---|
start |
Launch Metro dev server | --port, --reset-cache, --verbose |
bundle |
Create production bundle | --platform, --entry-file, --bundle-output, --sourcemap-output, --dev |
Error handling:
No Metro config found in ${cwd}— thrown asCLIErrorwhenmetro.config.jscannot be located
8.2.2 @react-native/metro-config
Purpose: Default Metro bundler configuration factory.
API: getDefaultConfig(projectRoot) — returns a complete Metro configuration object.
See Section 3.2 for the full configuration reference.
8.2.3 @react-native/dev-middleware
Purpose: Development server middleware with three capabilities:
- Inspector proxy — multiplexes CDP sessions between devices and debuggers (see Section 5.1)
- Debugger launcher — opens the debugger frontend in a browser or Electron shell
- DevTools integration — bridges React Native DevTools with the running app
8.2.4 @react-native/codegen
Purpose: Code generation from JS specs to native bindings.
| Component | Description |
|---|---|
| Flow Parser | Parses Flow-typed spec files |
| TypeScript Parser | Parses TS-typed spec files |
| C++ Generator | Produces headers and implementations for JSI bindings |
| Java Generator | Produces Java interfaces for Android TurboModules |
| ObjC Generator | Produces Objective-C protocols for iOS TurboModules |
8.2.5 @react-native/virtualized-lists
Purpose: Core list virtualization logic for FlatList and SectionList.
Extracted as a separate package for independent versioning. Contains the windowing algorithm, cell recycling logic, and scroll position management.
8.2.6 @react-native/normalize-color
Purpose: Color format normalization (13.5K chars).
Converts color strings and values to a 32-bit integer representation (0xRRGGBBAA) consumed by native view systems.
8.2.7 @react-native/assets-registry
Purpose: Runtime asset registration system.
API:
registerAsset(asset)— registers an asset, returns numeric IDgetAssetByID(id)— retrieves registered asset
8.2.8 @react-native/polyfills
Purpose: JavaScript polyfills (24.4K chars) injected before application code.
Fills gaps in the JS engine's Web API support. Loaded after InitializeCore but before any application module.
8.2.9 @react-native/babel-preset
Purpose: Standard Babel configuration for React Native projects.
Includes transforms for JSX, Flow stripping, TypeScript, and React Native-specific optimizations.
8.2.10 @react-native/babel-plugin-codegen
Purpose: Babel plugin that triggers native module codegen during the transform phase.
Detects TurboModule spec files (by convention) and invokes @react-native/codegen to generate native bindings.
8.2.11 @react-native/core-cli-utils
Purpose: Core CLI utility functions used by the community CLI plugin and framework integrations.
8.2.12 @react-native/new-app-screen
Purpose: Default screen shown in newly created React Native apps. Contains getting-started links and initial setup instructions.
8.3 Gradle Plugin Internals
| Component | Size | Description |
|---|---|---|
ReactPlugin |
— | Per-module plugin applied as com.facebook.react |
ReactRootProjectPlugin |
— | Root project plugin applied as com.facebook.react.rootproject |
| Utils | 48K chars | Build configuration helpers, dependency management, Gradle task registration |
| Tests | 60K chars | Comprehensive Kotlin test suite validating all plugin behavior |
Build specification:
| Property | Value |
|---|---|
| Language | Kotlin |
| JDK toolchain | 17 (compilation) |
| JVM target | 11 (runtime compatibility) |
| Dependencies | AGP, KGP, Gson, Guava, JavaPoet |
Plugin responsibilities:
- Register codegen Gradle tasks (spec file discovery, native code generation)
- Configure CMake for C++ native library compilation
- Set up Hermes bytecode compilation for release builds
- Manage dependency versions across React Native libraries
- Configure build variants (debug vs. release behavior differences)
- Register test tasks
- Configure JavaPoet for code generation at build time
8.4 Internal Test Framework: Fantom
The private/react-native-fantom/ package is React Native's internal test and benchmarking framework.
Components:
| Component | Purpose |
|---|---|
| Runner | Discovers and executes test/benchmark definitions |
| Tester | Assertion and verification utilities for testing React Native internals |
| Benchmarking | Timing measurement, statistical analysis, regression detection |
Design principles:
- Tests run in a controlled React Native environment (not a browser or Node.js)
- Benchmark mode enforces production configuration for meaningful results
- Integration testing of the full native-JS stack
Important
Fantom benchmarks enforce two runtime constraints: tests must be explicitly defined (
No benchmark tests definederror), and development mode must be disabled (Benchmarks should not be run in development modeerror). These guards prevent accidentally running benchmarks with debug overhead enabled.
8.5 Code Patterns and Conventions
8.5.1 Type System
| Aspect | Detail |
|---|---|
| Primary type system | Flow (v0.309.0) — used for core framework code |
| Secondary type system | TypeScript (5.8.3) — supported for consumers, used in codegen |
| TS config package | @react-native/typescript-config — base tsconfig.json for consumers |
| Codegen support | Both Flow and TS parsers for spec files |
8.5.2 Code Style
| Tool | Version | Scope |
|---|---|---|
| Prettier | 3.6.2 | Formatting (all JS/TS/Flow files) |
| ESLint | Via @react-native/eslint-config |
Linting (all JS/TS/Flow files) |
| ESLint Plugin | @react-native/eslint-plugin |
Custom React Native-specific rules |
| Monorepo Plugin | private/eslint-plugin-monorepo |
Internal workspace boundary rules |
8.5.3 Testing Conventions
| Test Type | Tool | Location | Pattern |
|---|---|---|---|
| Unit tests | Jest + @react-native/jest-preset |
__tests__/ alongside source |
*.test.js, *-test.js |
| Integration tests | Fantom | private/react-native-fantom/ |
Full-stack native+JS testing |
| E2E tests | Custom utilities | scripts/e2e/ |
End-to-end app testing |
| Release tests | Custom utilities | scripts/release-testing/ |
Pre-release validation |
| Gradle plugin tests | Kotlin test suite | packages/gradle-plugin/src/test/ |
60K chars of Kotlin tests |
| Type tests | Flow + TypeScript | Throughout codebase | Type-level correctness checks |
8.5.4 Error Handling Patterns
React Native uses typed error classes and descriptive messages:
// CLI errors — CLIError class with user-friendly messages
throw new CLIError(`No Metro config found in ${cwd}`);
// Parameter validation — thrown during spec parsing and runtime checks
throw new Error('Expected parameter to include ...');
throw new Error('Parameter cannot include ...');
// Runtime guards — defensive checks for expected but potentially missing APIs
throw new Error('Could not find the reload() implementation');
8.5.5 Module Organization Conventions
| Convention | Example | Description |
|---|---|---|
| Native specs | NativeDeviceInfo.js |
Files prefixed with Native containing TurboModule interfaces |
| Component specs | *NativeComponent.js |
Files containing codegenNativeComponent() calls |
| Platform extensions | .android.js, .ios.js |
Platform-specific module variants resolved by Metro |
| Test files | __tests__/*.test.js |
Co-located test directories |
| Internal APIs | src/private/ |
Non-public APIs |
8.6 Feature Flags
React Native uses a compile-time feature flag system (reactFeatureFlags SPM target, scripts/ feature flag utilities) to gate new functionality behind flags. This allows:
- Gradual rollout of new features
- A/B testing of renderer changes
- Fallback paths for experimental features
- Per-platform feature enablement
9. Integration Points
9.1 Metro Bundler Integration
Metro is the JavaScript bundler for React Native. It integrates through multiple packages:
| Touch Point | Package | Integration Type | Description |
|---|---|---|---|
| Configuration | @react-native/metro-config |
Config factory | Provides getDefaultConfig() with RN-specific defaults |
| Babel Transform | @react-native/babel-preset |
Babel preset | JS transpilation rules for React Native |
| Codegen Transform | @react-native/babel-plugin-codegen |
Babel plugin | Native module codegen during bundling |
| Dev Server | @react-native/community-cli-plugin |
CLI command | start command wraps Metro server |
| Bundling | @react-native/community-cli-plugin |
CLI command | bundle command wraps Metro bundler |
| Asset Resolution | @react-native/assets-registry |
Runtime | Assets discovered by Metro, registered at runtime |
| Module Resolution | @react-native/polyfills |
Serializer | Polyfills injected by Metro serializer |
Metro bundle request flow:
Device requests: GET /index.bundle?platform=android&dev=true
│
▼ Metro server receives request
│
▼ Resolves entry point (index.js)
│
▼ Walks dependency graph
│ (uses resolver config: react-native → browser → main fields)
│ (resolves .android.js / .ios.js platform extensions)
│
▼ Transforms each module (Babel + codegen plugin)
│
▼ Serializes modules in correct order
│ (InitializeCore → polyfills → app modules)
│
▼ Returns JavaScript bundle
9.2 Hermes Engine Integration
Hermes integrates at multiple levels across build and runtime:
Build-time integration:
JavaScript source files
│
▼ Metro bundler (produces JS bundle)
│
▼ Hermes compiler (hermesc)
│ Compiles JS → Hermes bytecode (.hbc)
│ Runs as part of Gradle (Android) / Xcode (iOS) build
│
▼ .hbc file bundled into APK/IPA
Runtime integration:
App launch
│
▼ Native code initializes HermesRuntime
│ (ReactCommon/hermes/ — JSI adapter)
│
▼ HermesRuntime implements jsi::Runtime interface
│ (engine-agnostic — same API as JSC or V8)
│
▼ Loads .hbc file directly (no parsing step)
│
▼ Executes InitializeCore → polyfills → app code
SDK utilities:
sdks/hermes-engine/— build helpers, version pinning, prebuild scripts
9.3 Native Platform Integration (Android)
App build.gradle
│
├── apply plugin: 'com.facebook.react'
│ │
│ ▼ ReactPlugin configures:
│ ├── Codegen tasks (scan specs → generate Java/C++)
│ ├── Hermes compilation task (JS → .hbc)
│ ├── CMake configuration (C++ library build)
│ ├── Dependency alignment (ReactAndroid version)
│ └── Build variant configuration (debug/release)
│
└── dependencies { implementation 'com.facebook.react:react-native:...' }
│
▼ ReactAndroid AAR
├── Java/Kotlin classes
├── .so native libraries (per ABI)
├── C++ headers
└── Resources
9.4 Native Platform Integration (iOS)
CocoaPods path:
Podfile
│
▼ pod install
│
▼ react-native.podspec + subspecs
├── React-Core (Libraries/ + Core runtime)
├── React-Fabric (Fabric renderer)
├── React-Hermes (Hermes engine integration)
├── Yoga (Layout engine)
├── React-RCTText (Text component)
├── React-RCTImage (Image component)
├── React-RCTNetwork (Networking)
└── ... (40+ pods total)
Swift Package Manager path:
Package.swift
│
▼ Xcode resolves SPM dependencies
│
▼ SPM Targets (40+)
├── yoga (layout engine)
├── jsi (JS interface)
├── reactFabric (Fabric renderer)
├── reactHermes (Hermes integration)
├── reactUtils (shared utilities)
├── reactFeatureFlags (feature flag system)
├── reactGraphics (graphics primitives)
├── reactCxxReact (C++ React core)
└── ... (see Package.swift for complete list)
9.5 Chrome DevTools Protocol (CDP) Integration
React Native implements a subset of the Chrome DevTools Protocol for debugging, profiling, and inspection.
Debugger UI (Chrome DevTools or React Native DevTools)
│
│ CDP over WebSocket (standard protocol)
▼
Inspector Proxy (@react-native/dev-middleware)
│
│ Multiplexed WebSocket (custom protocol)
│ Events: getPages, connect, disconnect, wrappedEvent
▼
jsinspector (ReactCommon/jsinspector/)
│
│ JSI calls to engine debugger
▼
Hermes Debugger / JSC Debugger
│
│ Engine-level debugging (breakpoints, stepping, eval)
▼
Application JavaScript execution
Supported CDP domains (subset of full CDP):
- Debugger — breakpoints, stepping, call stacks
- Runtime — expression evaluation, object inspection
- Console — console.log capture
- Network — request/response inspection (via native module bridge)
- Profiler — CPU profiling
9.6 CI and Release Integration
| Tool | Location | Size | Purpose |
|---|---|---|---|
| Release scripts | scripts/releases/ |
— | npm publish, version management, iOS prebuild, DotSlash |
| C++ API parser | scripts/cxx-api/parser/ |
86K chars | Doxygen-based API snapshot diffing (Python) |
| JS API tools | scripts/js-api/ |
— | TypeScript type generation, API surface diffing |
| E2E utilities | scripts/e2e/ |
— | End-to-end test infrastructure |
| Release testing | scripts/release-testing/ |
— | Pre-release validation suite |
| Shared utilities | scripts/shared/ |
— | Babel register, common helpers |
API surface protection workflow:
- Developer makes changes to public APIs
- CI runs
scripts/js-api/→ generates new TypeScript types → diffs against baseline - CI runs
scripts/cxx-api/parser/→ generates new C++ API snapshot → diffs against baseline - Any surface changes require explicit approval
ReactAndroid/api/files are separately tracked for Android API changes
10. Troubleshooting
10.1 Build Errors
No Metro config found in ${cwd}
Symptom: CLI throws CLIError when running start or bundle.
Cause: Metro configuration file (metro.config.js) not found in the working directory.
Fix: Ensure you are running the command from the project root where metro.config.js exists.
Verification: ls metro.config.js in your project root.
foojay-resolver-convention 0.5.0 incompatible with Gradle 9.0.0
Symptom: Android build fails with plugin resolution error after Gradle upgrade. Cause: The foojay-resolver-convention plugin 0.5.0 is incompatible with Gradle 9.0.0 (issue #56287). Fix: Upgrade the foojay-resolver-convention plugin to a compatible version, or pin Gradle below 9.0.0. Impact: Affects JDK toolchain auto-provisioning.
Inconsistent Podfile.lock checksums for hermes-engine
Symptom: pod install fails with checksum mismatch for hermes-engine (issue #54891).
Cause: Cached pod artifacts have stale checksums.
Fix:
pod cache clean hermes-engine --all
pod install --repo-update
Prevention: Add Pods/ to .gitignore and always run pod install from clean state in CI.
JDK version mismatch
Symptom: Gradle build fails with toolchain errors.
Cause: JDK version is not 17.
Fix: Ensure JAVA_HOME points to JDK 17. The Gradle plugin requires JDK 17 toolchain even though it targets JVM 11.
Node.js version incompatible
Symptom: Metro or CLI tools fail to start with version errors.
Cause: Node.js version outside supported range.
Fix: Use Node.js ^20.19.4, ^22.13.0, ^24.3.0, or >= 25.0.0.
10.2 Runtime Crashes
iOS app crashes on startup with TurboModule SIGABRT (iOS 26)
Symptom: App crashes immediately on launch with performVoidMethodInvocation SIGABRT (issue #54859, 28 comments).
Cause: TurboModule invocation failure during initialization on iOS 26.
Status: Active high-priority issue with significant community discussion.
Workaround: Track issue #54859 for the latest resolution.
EXC_BAD_ACCESS in production after upgrading to 0.79.6
Symptom: Sporadic EXC_BAD_ACCESS crashes in production builds (issue #53774).
Cause: Memory access violation in native code, potentially related to Fabric renderer lifecycle management.
Diagnosis: Collect crash logs with symbolicated stack traces. Look for patterns in the crash thread (UI thread vs. JS thread vs. background).
Workaround: Track issue #53774.
Could not find the reload() implementation
Symptom: Error during development when React Refresh (Fast Refresh) attempts to initialize.
Cause: The React Refresh runtime module is not available or was not properly injected by the Babel transform.
Fix: Ensure react-refresh is installed as a dependency and @react-native/babel-preset is configured in your Babel config.
10.3 Development Server Issues
Metro server port conflict
Symptom: Metro fails to start, error about port 8081 being in use. Cause: Another process (possibly another Metro instance) is occupying port 8081. Fix:
- Option A: Kill the process on 8081
- Option B: Set
RCT_METRO_PORT=8082(or any available port) - Option C: Set
server.portinmetro.config.js
Intermittent "Network request failed" error
Symptom: fetch requests fail intermittently during development (issue #56480).
Cause: Network layer instability, potentially related to connection pooling or timeout handling in the native HTTP client.
Workaround: Implement retry logic in the application layer. Track issue #56480.
Metro cache corruption
Symptom: Build errors that don't match source code, stale module resolution.
Cause: Metro's filesystem cache is stale or corrupted.
Fix: Clear the cache: start Metro with --reset-cache flag.
10.4 Android-Specific Issues
Broken Code Completion / Intellisense in Android Studio
Symptom: Android Studio's code completion and Intellisense stop working for React Native Android code (issue #55517, 13 comments). Cause: IDE indexing issues with the React Native Android module structure. Workaround: Track issue #55517 for workarounds. Try: File → Invalidate Caches / Restart.
HermesSamplingProfiler JNI mapping error
Symptom: Profiler disable JNI method is mapped to ::enable, causing incorrect profiler behavior (issue #56126).
Cause: Incorrect JNI method binding in the Hermes sampling profiler.
Impact: Profiling data may be incorrect or profiler may not stop properly.
Workaround: Track issue #56126.
Heap snapshot fails — OkHttp WebSocket MAX_QUEUE_SIZE overflow
Symptom: Taking a heap snapshot via DevTools crashes with OkHttp WebSocket queue size exceeded (issue #56470). Cause: Heap snapshot data volume exceeds OkHttp's default WebSocket write queue limit. Workaround: Use smaller heaps for snapshots, or increase OkHttp queue limits in a custom native module. Track issue #56470.
getStatusBarHeightPx initialized before DecorView attached
Symptom: Status bar height returns 0 or incorrect value, causing layout issues (issue #53251).
Cause: The status bar height query executes before the Activity's DecorView is attached to the window hierarchy.
Workaround: Defer status bar height queries. Use View.post() or ViewTreeObserver to ensure DecorView is attached. Track issue #53251.
KeyboardAvoidingView under Android 15
Symptom: KeyboardAvoidingView layout behavior is incorrect on Android 15 with edge-to-edge (issue #49759).
Cause: Android 15's edge-to-edge display changes affect how keyboard insets are calculated and reported.
Workaround: Track issue #49759 for platform-specific workarounds.
10.5 UI and Layout Issues
RefreshControl visual jump
Symptom: Pull-to-refresh causes a visual jump in the scroll position (issue #31461). Since: React Native 0.64.0 Cause: Refresh indicator insertion disrupts scroll offset calculation. Status: Long-standing issue. Track issue #31461.
Nested View and Text vertical alignment
Symptom: Views nested inside Text components have incorrect vertical alignment (issue #31955). Cause: Yoga layout calculation for mixed inline and block elements does not perfectly match CSS vertical alignment rules. Workaround: Use explicit padding/margin to manually compensate for alignment differences. Track issue #31955.
letterSpacing not working properly
Symptom: The letterSpacing style property produces incorrect or inconsistent results across platforms (issue #54823).
Cause: Platform-specific text rendering differences in how letter spacing is applied.
Workaround: Track issue #54823. Test on both platforms and adjust values per-platform if needed.
Nested text not focusable by hardware keyboards
Symptom: Text within nested <Text> components cannot receive focus from hardware keyboard navigation (issue #35194).
Cause: Accessibility focus handling for nested text elements does not propagate keyboard focus correctly.
Workaround: Track issue #35194. Flatten text nesting where keyboard accessibility is critical.
10.6 Animation Issues
Animated Bug in React Navigation (iOS)
Symptom: Animation glitches when using React Native's Animated API with React Navigation on iOS (issue #56347).
Cause: Interaction between the native Animated driver and React Navigation's transition animations.
Workaround: Track issue #56347. Consider using react-native-reanimated as an alternative animation library.
10.7 Codegen and Type Errors
Expected parameter to include / Parameter cannot include
Symptom: Codegen or runtime throws parameter validation error during spec parsing or method invocation. Cause: A key-value parameter does not match expected format constraints defined in the spec. Fix: Review the spec file to ensure parameter types match the expected schema. Check for typos in parameter names and type annotations.
10.8 Benchmarking Errors
No benchmark tests defined
Symptom: Fantom benchmark runner exits with error. Cause: No test files with benchmark definitions were found in the expected locations. Fix: Ensure benchmark test files are in the expected directory and use the correct Fantom benchmark API to define benchmarks.
Benchmarks should not be run in development mode
Symptom: Fantom refuses to run benchmarks, exits with error.
Cause: NODE_ENV is set to development or the React Native __DEV__ flag is true.
Fix: Run benchmarks with production/release configuration. Ensure __DEV__ is false and NODE_ENV is production.
10.9 General Debugging Strategies
| Scenario | Tools | Approach |
|---|---|---|
| JS crash | LogBox, Metro console | Check LogBox overlay in app, read Metro terminal output for stack trace |
| Native crash (Android) | adb logcat |
Run adb logcat *:E to filter for error-level native logs |
| Native crash (iOS) | Xcode | Use Xcode debugger and crash reports in Organizer |
| Layout issues | Inspector, Yoga | Use React Native DevTools inspector to examine shadow tree; enable Yoga debug logging |
| Network issues | CDP Network panel | Use React Native DevTools Network tab to inspect requests/responses |
| Performance (JS) | Hermes profiler | Use Hermes sampling profiler for JS-side bottlenecks |
| Performance (Android) | Systrace | Android Systrace for native-side profiling |
| Performance (iOS) | Instruments | Xcode Instruments for native-side profiling (Time Profiler, Allocations) |
| TurboModule errors | Codegen output | Verify generated code matches spec; check module registration in app startup |
| Metro bundling | Cache reset | Clear Metro cache with --reset-cache flag |
| Build failures | Dependency tree | Check for version mismatches in yarn.lock, verify environment (Node, JDK, Ruby versions) |
Warning
When debugging native crashes, always use symbolicated stack traces. Unsymbolicated traces from Hermes bytecode or stripped native libraries are not useful for diagnosis. On Android, use
ndk-stackto symbolicate native crashes. On iOS, use Xcode's crash report symbolicator oratoscommand.
10.10 Common Environment Issues
| Issue | Symptom | Resolution |
|---|---|---|
| Wrong Node version | Metro startup failure | Install Node.js matching ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 |
| Wrong JDK version | Gradle toolchain error | Set JAVA_HOME to JDK 17 |
Missing ANDROID_HOME |
Android build fails | Set ANDROID_HOME to Android SDK path |
| Missing Ruby | pod install fails |
Install Ruby >= 2.6.10 |
| Yarn version mismatch | Workspace resolution errors | Use Yarn 1.22.22 exactly |
| Missing Xcode CLI tools | iOS build fails | Run xcode-select --install |
10.11 Upgrade Troubleshooting
Upgrading React Native between versions is a common source of issues. Here are patterns for diagnosing upgrade-related problems:
Native Module Compatibility After Upgrade
Symptom: Third-party native modules crash or fail to initialize after React Native upgrade. Cause: TurboModule interface changes between versions, or codegen output format changes. Diagnosis:
- Check if the native module has a version compatible with the new React Native version
- Re-run codegen to regenerate native bindings
- Check for breaking changes in the React Native changelog
- Verify the module's spec file (Native*.js) matches the expected TurboModule interface
CocoaPods Resolution Failures After Upgrade
Symptom: pod install fails with dependency conflicts after upgrading React Native.
Cause: Podspec version constraints conflict between the new React Native version and cached pods.
Fix:
cd ios
rm -rf Pods Podfile.lock
pod cache clean --all
pod install --repo-update
Gradle Build Failures After Upgrade
Symptom: Android build fails with unresolved dependencies or incompatible plugin versions. Cause: React Native Gradle plugin version mismatch or AGP incompatibility. Diagnosis:
- Verify
com.facebook.reactplugin version matches the React Native version - Check AGP version compatibility
- Clean the Gradle cache:
./gradlew clean - Delete
.gradle/directory for a full rebuild
Metro Bundle Errors After Upgrade
Symptom: Metro reports module resolution errors or transform failures.
Cause: Changed module structure, updated Babel transforms, or stale cache.
Fix: Start Metro with --reset-cache to clear the transformer and resolver caches.
Hermes Version Mismatch
Symptom: App crashes on startup with Hermes-related errors after upgrade. Cause: Hermes bytecode version from previous build is incompatible with the new Hermes runtime. Fix: Clean build to regenerate Hermes bytecode:
- Android:
./gradlew clean - iOS: Clean build folder in Xcode (Cmd+Shift+K)
10.12 Production Monitoring Checklist
| Check | Method | Frequency |
|---|---|---|
| JS crashes | Error boundary + crash reporting SDK | Real-time |
| Native crashes | Platform crash reporting (Firebase Crashlytics, Sentry) | Real-time |
| ANR/hang detection | Android vitals, Xcode Organizer | Daily |
| JS bundle size | Metro bundle size report | Per-release |
| Startup time | Custom timing instrumentation | Per-release |
| Memory usage | Platform profiling tools | Weekly |
| Frame drops | Custom FPS monitoring | Continuous |
10.13 Debugging WebSocket Close Codes
When inspector or debugger connections drop unexpectedly, the WebSocket close code reveals the cause:
| Close Code | Diagnosis | Action |
|---|---|---|
PAGE_NOT_FOUND |
The debug target page was destroyed (navigation, component unmount) | Reconnect to the new page via /json/list |
CONNECTION_LOST |
Network interruption between proxy and device | Check WiFi/USB connection, restart Metro |
RECREATING_DEVICE |
App was backgrounded/foregrounded or restarted | Wait for device to re-register, reconnect |
NEW_DEBUGGER_OPENED |
Another DevTools window stole the session | Close the other DevTools window |
UNREGISTERED_DEVICE |
Device disconnected entirely | Verify device is connected and app is running |
INCORRECT_URL |
Client sent malformed WebSocket URL | Fix the URL format (check device_id and page_id parameters) |
10.14 Common Performance Anti-Patterns
| Anti-Pattern | Impact | Fix |
|---|---|---|
| Inline style objects in render | Creates new objects every render, causing unnecessary re-renders | Use StyleSheet.create() outside render |
Large FlatList without getItemLayout |
Forces measurement of every item, slow initial render | Provide getItemLayout for fixed-height items |
| Unthrottled scroll handlers | onScroll fires on every frame, JS thread saturation |
Use scrollEventThrottle prop |
| Synchronous storage reads on startup | Blocks JS thread during initialization | Use async reads, preload in native |
| Console.log in production | String serialization + native logging overhead | Strip console calls in production builds |
| Non-memoized callbacks passed to children | Causes unnecessary child re-renders | Use useCallback / useMemo |
| Large images without resizing | Native memory pressure, slow rendering | Use resizeMode and serve appropriately sized images |
10.16 Log Collection Reference
| Platform | Log Type | Collection Command/Location |
|---|---|---|
| Android | Native logs | adb logcat |
| Android | React Native logs | adb logcat ReactNative:V ReactNativeJS:V *:S |
| Android | Crash reports | adb bugreport |
| iOS | Native logs | Console.app or log stream |
| iOS | Crash reports | Xcode Organizer → Crashes |
| Metro | Bundle errors | Metro terminal output |
| Metro | Request log | Metro terminal (verbose mode) |
11. Contributing
11.1 Repository Tooling
| Tool | Version | Purpose | Required |
|---|---|---|---|
| Yarn | 1.22.22 | Package management, workspace orchestration | Yes |
| Flow | ^0.309.0 | Type checking (primary for core code) | Yes (core development) |
| TypeScript | 5.8.3 | Type checking (consumers, codegen) | Yes (TS-related changes) |
| Jest | ^29.7.0 | Unit and integration testing | Yes |
| Prettier | 3.6.2 | Code formatting | Yes |
| ESLint | Via @react-native/eslint-config |
Linting | Yes |
11.2 Workspace Structure
The monorepo uses Yarn workspaces. All packages in packages/ and private/ are workspace members. Dependencies between workspace packages are resolved locally (symlinked in node_modules).
Key workspace commands:
yarn install— installs all dependencies across all workspacesyarn workspace <name> <command>— runs a command in a specific workspaceyarn workspaces run <command>— runs a command in all workspaces
11.3 Testing Strategy
| Level | Tool | Location | Run Command |
|---|---|---|---|
| Unit tests | Jest + @react-native/jest-preset |
__tests__/ alongside source |
yarn jest |
| Integration tests | Fantom | private/react-native-fantom/ |
Framework-specific runner |
| E2E tests | Custom utilities | scripts/e2e/ |
See scripts |
| Release tests | Custom utilities | scripts/release-testing/ |
See scripts |
| Gradle plugin tests | Kotlin test suite | packages/gradle-plugin/src/test/ |
./gradlew test |
| Type tests | Flow | Throughout codebase | yarn flow |
| Type tests | TypeScript | Throughout codebase | yarn tsc |
| Lint | ESLint + Prettier | Throughout codebase | yarn lint |
11.4 API Surface Tracking
Two automated systems prevent unintentional API breakage:
JavaScript API tracking:
- Location:
scripts/js-api/ - Method: generates TypeScript type definitions from source, diffs against committed baseline
- Trigger: CI runs on every PR that touches public JS APIs
- Action required: update baseline if change is intentional
C++ API tracking:
- Location:
scripts/cxx-api/parser/ - Size: 86K chars of Python code
- Method: Doxygen-based parser creates API snapshots, diffs against baseline
- Trigger: CI runs on every PR that touches C++ public headers
- Action required: update baseline if change is intentional
Android API tracking:
- Location:
ReactAndroid/api/ - Method: API surface files committed to version control
- Trigger: CI checks for modifications
- Action required: explicit approval for changes
11.5 Reference App
The private/helloworld/ package serves as the canonical reference application:
- Exercises the full framework stack (Fabric, TurboModules, codegen, native builds)
- Used in CI for integration testing
- Validates both Android and iOS build pipelines
- Tests debug and release configurations
Tip
When making changes to core React Native, build and test against the
private/helloworld/app before submitting. It exercises codegen, TurboModules, Fabric, and the full native build pipeline for both platforms, catching integration issues that unit tests miss.
11.6 Monorepo Conventions
| Convention | Rule |
|---|---|
| Package naming | @react-native/<name> for public packages |
| Internal packages | private/<name> directory, not published to npm |
| Version alignment | All packages in the monorepo share the same version |
| Dependency management | Use workspace protocol for inter-package dependencies |
| Build order | Defined by dependency graph; no manual ordering needed |
11.7 Architecture Decision Context
Understanding the architectural choices helps contributors make consistent decisions:
Why JSI over the Bridge: The original async bridge required JSON serialization for every cross-language call. For high-frequency operations (layout queries, animation frames, touch events), this overhead was unacceptable. JSI provides direct C++ function calls from JavaScript, eliminating serialization entirely. The tradeoff is increased complexity in memory management (C++ objects must be carefully lifecycle-managed from JS) and debugging difficulty (synchronous native calls can block the JS thread).
Why Codegen: Without codegen, native module developers had to manually write boilerplate for type marshaling, argument parsing, and error handling. This was error-prone and led to type mismatches between JS and native. Codegen generates this boilerplate from spec files, ensuring type safety at compile time.
Why Fabric over UIManager: The legacy UIManager maintained the shadow tree in JavaScript and communicated with native via the async bridge. This meant layout was computed in JS, serialized, sent to native, deserialized, and then applied. Fabric moves the shadow tree to C++, layout computation to Yoga (C++), and uses JSI for synchronous mounting instructions. The result is faster rendering and the ability to perform layout and rendering in a single frame.
Why Hermes over JSC/V8: JavaScriptCore and V8 were designed for browsers — they optimize for peak throughput at the cost of startup time and memory. Hermes is designed for mobile: it precompiles to bytecode (eliminating parse time), has a smaller binary size, and uses a garbage collector tuned for mobile memory constraints.
Why Yoga over system layout: Android and iOS each have their own layout systems (ConstraintLayout/LinearLayout and AutoLayout respectively). Using either would mean implementing layout logic twice and dealing with subtle platform differences. Yoga provides a single Flexbox implementation in C++ that produces identical layout results on both platforms.
12. Advanced Topics
12.1 Threading Model
React Native's threading model is central to understanding its behavior and debugging performance issues.
Thread inventory:
| Thread | Name | Purpose | Managed By |
|---|---|---|---|
| JS Thread | mqt_js (Android) |
Runs JavaScript code, React reconciliation | JSI Runtime |
| Main/UI Thread | Main thread | Mounts/updates native views, handles touch events | Platform OS |
| Background Thread | Shadow thread | Shadow tree cloning, diff computation | Fabric Scheduler |
| Native Modules Thread | mqt_native_modules |
Legacy native module execution (pre-TurboModule) | Bridge (legacy) |
Thread communication patterns:
JS Thread UI Thread
│ │
│ React render() produces │
│ shadow tree mutations │
│ │ │
│ ▼ │
│ Scheduler │
│ (batches mutations) │
│ │ │
│ ▼ (dispatch to UI) │
│ │
│ Mounting Layer
│ creates/updates
│ native views
│ │
│ ◄── touch event ─────────│
│ │
│ JS event handler runs │
│ may trigger re-render │
│ │ │
│ ▼ (cycle repeats) │
Note
With TurboModules and JSI, native calls from JavaScript execute synchronously on the JS thread. This means a slow native operation (e.g., file I/O, heavy computation) will block the JS thread and freeze the UI. Use async native methods for operations that may take significant time.
13.2 Memory Management Across Boundaries
The JSI boundary between JavaScript and C++ introduces memory management challenges:
JavaScript → C++ (HostObjects):
- C++ objects exposed to JS via
jsi::HostObjectare prevented from garbage collection as long as JS holds a reference - When JS releases all references, the C++ destructor is called
- Prevent memory leaks by avoiding circular references between JS and C++ objects
C++ → JavaScript:
- C++ code can hold
jsi::Valuereferences to JS objects - These references must be explicitly released when no longer needed
jsi::WeakObjectprovides weak references that don't prevent GC
Platform Native → C++ → JavaScript:
- Native platform objects (Java/ObjC) are bridged through C++ JNI/ObjC++ wrappers
- Three-layer reference chains require careful lifecycle management
- TurboModule codegen handles most of this automatically
13.3 Event System Architecture
React Native's event system spans all three layers:
Native Touch/Gesture/Keyboard Event
│
▼ Platform event system (Android MotionEvent / iOS UITouch)
│
▼ Native event handler in ReactAndroid/React
│
▼ Fabric EventEmitter (C++)
│ (ReactCommon/react/renderer/core/EventEmitter)
│ Dispatches via Scheduler to JS thread
│
▼ React event handler in JavaScript
│ (SyntheticEvent, W3C-compatible)
│ onPress, onScroll, onChangeText, etc.
Android event subsystem (37K chars, 24 files in uimanager events):
| Event Category | Description |
|---|---|
| Touch events | onTouchStart, onTouchMove, onTouchEnd, onTouchCancel |
| Scroll events | onScroll, onMomentumScrollBegin/End |
| Focus events | onFocus, onBlur |
| Text input events | onChangeText, onSubmitEditing, onSelectionChange |
| Layout events | onLayout |
| Keyboard events | onKeyPress |
Fabric event subsystem (5.4K chars): Fabric-specific event dispatch that bypasses the legacy UIManager path, using direct C++ EventEmitter → JSI → JS delivery.
13.4 Module Resolution Deep Dive
Metro's module resolution is a critical piece of React Native's architecture:
Resolution order for require('some-module'):
- Check if it's a Node.js built-in (rejected — React Native does not include Node built-ins)
- Check
resolverMainFieldsin package.json:react-nativefield (React Native-specific entry point)browserfield (browser-compatible entry point)mainfield (default entry point)
- Check platform extensions:
some-module.android.js(on Android)some-module.ios.js(on iOS)some-module.js(fallback)
- Check
node_modules/directories (up the directory tree)
Why react-native field first:
Many libraries ship platform-specific code via the react-native field in package.json. For example, a library might have:
{
"main": "lib/index.js",
"browser": "lib/browser.js",
"react-native": "lib/react-native.js"
}
The react-native entry typically imports native modules or uses React Native-specific APIs.
13.5 Codegen Type Mapping
The codegen system maps JavaScript types to native types:
Primitive type mapping:
| JS/Flow/TS Type | C++ Type | Java Type | ObjC Type |
|---|---|---|---|
boolean |
bool |
boolean |
BOOL |
number (int) |
int |
int |
NSInteger |
number (double) |
double |
double |
double |
string |
std::string |
String |
NSString * |
null |
nullptr |
null |
nil |
Complex type mapping:
| JS/Flow/TS Type | C++ Type | Java Type | ObjC Type |
|---|---|---|---|
Object |
jsi::Object |
ReadableMap |
NSDictionary * |
Array<T> |
jsi::Array |
ReadableArray |
NSArray * |
Promise<T> |
callback pair | Promise |
RCTPromiseResolveBlock + RCTPromiseRejectBlock |
?T (nullable) |
std::optional<T> |
@Nullable T |
nullable T |
12.6 Data Flow Patterns
Understanding how data flows through React Native is essential for debugging and performance optimization.
12.6.1 Props Flow (Parent to Child)
Parent Component (JS)
│ <Child color="red" />
▼
React Reconciler (JS)
│ Detects prop change
▼
Shadow Tree Mutation (C++)
│ Clones ShadowNode with new Props
▼
Yoga Layout (C++)
│ Recomputes layout if style props changed
▼
Mounting (Native)
│ Updates native view property
▼
Screen update
12.6.2 Event Flow (Native to JS)
User touches screen
│
▼
Platform Touch System
│ Android: MotionEvent / iOS: UITouch
▼
Native Event Handler
│ ReactAndroid uimanager events (37K chars, 24 files)
│ or React/Fabric event handlers
▼
Fabric EventEmitter (C++)
│ Wraps native event as SyntheticEvent
▼
Scheduler dispatches to JS thread
│
▼
JS Event Handler
│ onPress={() => setState(...)}
▼
React reconciliation (if state changed)
│ New render cycle begins
12.6.3 Native Module Call Flow
JS Code: NativeModule.getDeviceName()
│
▼ JSI synchronous call
│
C++ TurboModule Binding
│ Generated by @react-native/codegen
│ Type-checks arguments
▼
Platform Implementation
│ Android: Java method via JNI
│ iOS: ObjC method via ObjC++ bridge
▼
Return value (synchronous for sync methods)
or Promise resolution (for async methods)
▼
JS receives result
12.6.4 Bundle Loading Flow
App Launch
│
▼ Native code starts
│
▼ Initialize Hermes/JSC runtime (via JSI)
│
▼ Load JS bundle
│ Debug: fetch from Metro server (HTTP GET)
│ Release: load .hbc from app resources
│
▼ Execute InitializeCore
│ Sets up __DEV__, global, error handling
│
▼ Execute polyfills (@react-native/polyfills, 24.4K chars)
│
▼ Execute application entry point
│ AppRegistry.registerComponent()
│
▼ First render
│ React reconciler → Fabric → Yoga → Mount
│
▼ App interactive
12.7 Inspector Proxy Session Lifecycle
Understanding the full inspector proxy session lifecycle helps debug connectivity issues:
1. App launches on device
│
▼
2. Device registers with proxy
│ WS connect: /inspector/device?device=ABC&name=iPhone&app=com.myapp
│ Proxy assigns device entry
│
▼
3. Proxy queries device for pages
│ Proxy → Device: { event: "getPages" }
│ Device → Proxy: [{ id: 1, title: "React Native", ... }]
│
▼
4. User opens DevTools
│ WS connect: /inspector/debug?device=ABC&page=1
│ Proxy → Device: { event: "connect", payload: { pageId: 1 } }
│
▼
5. Debug session active
│ Debugger → Proxy → Device: { event: "wrappedEvent", payload: { cdpMessage } }
│ Device → Proxy → Debugger: { event: "wrappedEvent", payload: { cdpResponse } }
│ (All CDP traffic wrapped in wrappedEvent envelopes)
│
▼
6. Session ends (various triggers)
│ User closes DevTools → Proxy → Device: { event: "disconnect" }
│ App crashes → Device WS closes → Proxy sends close to Debugger
│ Network drops → Both sides detect close via WS ping/pong timeout
Capabilities negotiation:
When the proxy queries pages, each page reports its capabilities. The debugger uses these to determine available features:
| Capability | true |
false |
|---|---|---|
nativePageReloads |
Reload button works | Reload button hidden |
nativeSourceCodeFetching |
Source tab shows actual files | Source tab shows bundled code only |
supportsMultipleDebuggers |
Multiple DevTools windows allowed | Second DevTools steals session |
12.8 Build Variant Differences
| Aspect | Debug Build | Release Build |
|---|---|---|
| JS Engine | Hermes (interpreted) or JSC | Hermes (bytecode precompiled) |
__DEV__ |
true |
false |
| LogBox | Enabled | Stripped |
| Inspector | Available | Stripped |
| Dev Menu | Available | Stripped |
| Source Maps | Generated and served | Optional, not served |
| Metro Server | Required (live bundling) | Not used (bundle in app) |
| ProGuard/R8 | Disabled | Enabled (Android) |
| Bitcode | Disabled | Optional (iOS) |
| Native symbols | Full | Stripped |
| Performance | Slower (dev overhead) | Optimized |
Tip
Always test in release mode before shipping. Debug mode includes significant overhead: LogBox error boundary, inspector proxy connections, unoptimized Hermes interpretation, and dev-only code paths. Performance bugs that don't reproduce in release mode are often caused by debug-only overhead.
13. Quick Reference
13.1 Complete Package Registry
| Package | npm Name | Purpose | Key Exports |
|---|---|---|---|
| Core | react-native |
Main framework | Components, APIs, runtime |
| CLI Plugin | @react-native/community-cli-plugin |
CLI commands | start, bundle |
| Metro Config | @react-native/metro-config |
Metro defaults | getDefaultConfig() |
| Dev Middleware | @react-native/dev-middleware |
Inspector proxy | Middleware factory |
| Debugger Frontend | @react-native/debugger-frontend |
DevTools UI | Chrome DevTools build |
| Debugger Shell | @react-native/debugger-shell |
Electron shell | DevTools app |
| Babel Preset | @react-native/babel-preset |
Babel config | Preset function |
| Babel Codegen | @react-native/babel-plugin-codegen |
Codegen plugin | Babel plugin |
| Codegen | @react-native/codegen |
Code generator | Flow/TS parsers, generators |
| ESLint Config | @react-native/eslint-config |
ESLint rules | Config object |
| ESLint Plugin | @react-native/eslint-plugin |
ESLint plugin | Custom rules |
| Jest Preset | @react-native/jest-preset |
Jest config | Preset object |
| Assets Registry | @react-native/assets-registry |
Asset system | registerAsset, getAssetByID |
| Normalize Color | @react-native/normalize-color |
Color utils | normalizeColor() |
| Virtualized Lists | @react-native/virtualized-lists |
List rendering | VirtualizedList |
| New App Screen | @react-native/new-app-screen |
Default screen | React components |
| TS Config | @react-native/typescript-config |
TS config | tsconfig.json base |
| Polyfills | @react-native/polyfills |
JS polyfills | Runtime polyfills |
| Core CLI Utils | @react-native/core-cli-utils |
CLI utilities | Utility functions |
| Gradle Plugin | com.facebook.react |
Android plugin | Gradle plugin |
13.2 Key File Locations
| File/Directory | Purpose |
|---|---|
packages/react-native/Libraries/ |
JavaScript framework code (Core, Components, Network, Lists, LogBox, Settings) |
packages/react-native/ReactAndroid/ |
Android native implementation (Java/Kotlin) |
packages/react-native/ReactAndroid/api/ |
Android public API surface definition |
packages/react-native/ReactCommon/ |
Shared C++ core (JSI, Fabric, Yoga, TurboModules, jsinspector) |
packages/react-native/ReactCommon/react/renderer/core/ |
Fabric renderer core (82 files, 240K chars) |
packages/react-native/ReactCommon/react/renderer/scheduler/ |
Scheduler (9 files, 32K chars) |
packages/react-native/ReactCommon/yoga/ |
Yoga layout engine |
packages/react-native/ReactCxxPlatform/ |
Cross-platform C++ layer |
packages/react-native/React/ |
iOS native implementation (Obj-C/Swift) |
packages/react-native/React/Fabric/Utils/ |
iOS Fabric utilities (10 files, 9.2K chars) |
packages/react-native/src/private/ |
Private JS APIs (renderer, web APIs) |
packages/react-native/sdks/hermes-engine/ |
Hermes engine utilities |
packages/react-native/scripts/ |
Codegen, feature flags, CocoaPods, iOS prebuild |
packages/react-native/Package.swift |
Swift Package Manager definition (40+ targets) |
packages/gradle-plugin/ |
Android Gradle plugin source (Kotlin) |
packages/gradle-plugin/src/main/kotlin/.../utils/ |
Plugin utilities (48K chars) |
packages/gradle-plugin/src/test/ |
Plugin tests (60K chars) |
private/helloworld/ |
Reference test application |
private/react-native-fantom/ |
Internal test/benchmark framework |
private/eslint-plugin-monorepo/ |
Monorepo ESLint rules |
scripts/releases/ |
Release automation |
scripts/cxx-api/parser/ |
C++ API snapshot tool (Python, 86K chars) |
scripts/js-api/ |
JS API tracking tool |
scripts/e2e/ |
E2E test utilities |
scripts/release-testing/ |
Release test utilities |
scripts/shared/ |
Shared utilities (babel register) |
13.3 Default Ports and Endpoints
| Service | Default Port | Endpoint | Protocol |
|---|---|---|---|
| Metro Dev Server | 8081 | http://localhost:8081 |
HTTP |
| JS Bundle | 8081 | GET /index.bundle?platform={platform}&dev={bool} |
HTTP |
| Inspector list | 8081 | GET /json/list |
HTTP |
| Inspector version | 8081 | GET /json/version |
HTTP |
| Device registration | 8081 | /inspector/device?device={id}&name={name}&app={bundle_id} |
WebSocket |
| Debugger connection | 8081 | /inspector/debug?device={device_id}&page={page_id} |
WebSocket |
13.4 Error Quick Reference
| Error Message | Source | Likely Cause | Section |
|---|---|---|---|
No Metro config found in ${cwd} |
community-cli-plugin | Missing metro.config.js | 10.1 |
Expected parameter to include |
Parameter parsing | Malformed key-value parameter | 10.7 |
Parameter cannot include |
Parameter parsing | Invalid characters in parameter | 10.7 |
Could not find the reload() implementation |
React Refresh | Missing react-refresh setup | 10.2 |
No benchmark tests defined |
Fantom | No benchmark tests found | 10.8 |
Benchmarks should not be run in development mode |
Fantom | Development mode enabled | 10.8 |
13.5 Environment Variable Quick Reference
| Variable | Default | Required | Purpose | Section |
|---|---|---|---|---|
ANDROID_HOME |
— | Android builds | Android SDK path | 3.1 |
RCT_METRO_PORT |
8081 | No | Metro server port | 3.1 |
NODE_ENV |
— | No | Environment mode (development/production/test) | 3.1 |
REACT_NATIVE_DEBUGGER_FRONTEND_PATH |
— | No | Custom debugger frontend | 3.1 |
DEBUG |
— | No | Verbose Metro/middleware logging | 3.1 |
SKIP |
— | No | Skip flag for CLI operations | 3.1 |
FANTOM_* |
— | No | Fantom test framework config | 3.1 |
13.6 Version Requirements Summary
| Tool | Required Version |
|---|---|
| Node.js | ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0 |
| Yarn | 1.22.22 |
| JDK | 17 |
| Ruby | >= 2.6.10 |
| React | 19.2.3 |
| TypeScript | 5.8.3 |
| Flow | ^0.309.0 |
13.7 Known Issues Summary
| Issue | Platform | Status | GitHub |
|---|---|---|---|
| TurboModule SIGABRT on iOS 26 startup | iOS | Active (28 comments) | #54859 |
| Broken Intellisense in Android Studio | Android | Active (13 comments) | #55517 |
| Animated bug with React Navigation | iOS | Active | #56347 |
| Hermes profiler JNI mapping error | Android | Active | #56126 |
| Intermittent network request failures | Both | Active | #56480 |
| Heap snapshot OkHttp overflow | Android | Active | #56470 |
| foojay-resolver Gradle 9.0.0 incompat | Android | Active | #56287 |
| StatusBar height before DecorView | Android | Active | #53251 |
| Podfile.lock hermes-engine checksums | iOS | Active | #54891 |
| EXC_BAD_ACCESS after 0.79.6 upgrade | iOS | Active | #53774 |
| KeyboardAvoidingView Android 15 | Android | Active | #49759 |
| RefreshControl visual jump | Both | Open since 0.64.0 | #31461 |
| Nested View/Text vertical alignment | Both | Open | #31955 |
| letterSpacing rendering | Both | Active | #54823 |
| Nested text keyboard focus | Both | Open | #35194 |