Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

React Native — Administrator & Developer Guide

Generated May 2026 from facebook/react-native at ba204fa

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

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 Runtime implementation.

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_HOME points 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-native before browser before main) 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:

  1. Codegen tasks — generates native bindings from JS spec files
  2. Hermes compilation — compiles JS to Hermes bytecode for release builds
  3. Native library compilation — configures CMake/ndk-build for C++ code
  4. Dependency management — aligns React Native library versions
  5. 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.swift is 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:

  1. Command-line --port flag (highest priority)
  2. RCT_METRO_PORT environment variable
  3. server.port in metro.config.js
  4. Default: 8081

4.1.2 bundle — Production Bundle

Creates an optimized JavaScript bundle for deployment to devices.

Bundle process:

  1. Resolves all module dependencies starting from the entry point
  2. Applies Babel transforms (including codegen for TurboModule specs)
  3. Tree-shakes unused code (in production mode)
  4. Concatenates modules into a single file
  5. Generates source map (optional)
  6. Outputs platform-specific bundle (.android.js or .ios.js extensions 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:

  1. Codegen phase — scans for JS spec files, generates native bindings
  2. Bundle phase — invokes Metro to create the JS bundle (release builds)
  3. Hermes phase — compiles JS bundle to Hermes bytecode (when Hermes enabled)
  4. Native build — configures CMake for C++ compilation with correct includes
  5. 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 runtime
  • React-Fabric — Fabric renderer
  • React-Hermes — Hermes engine integration
  • Yoga — Layout engine
  • 40+ additional subspecs for individual modules

Caution

Inconsistent Podfile.lock checksums for hermes-engine have 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 in Podfile.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 install step)
  • 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:

  1. Babel processes each JS file through the transform pipeline
  2. The codegen plugin detects spec files (by convention: Native*.js with TurboModule interface)
  3. On detection, it triggers the codegen pipeline for that spec
  4. 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:

  1. Server starts, loads metro.config.js
  2. Watches filesystem for source changes
  3. Devices connect and request bundles
  4. On file change: invalidates affected modules, pushes updates via HMR
  5. Inspector proxy runs in-process, manages debug sessions

Server port configuration precedence:

  1. CLI --port flag
  2. RCT_METRO_PORT environment variable
  3. metro.config.js → server.port
  4. 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 the wrappedEvent protocol.

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 ID
  • getAssetByID(id) — retrieves a registered asset by its numeric ID

Asset resolution flow:

  1. Metro's asset resolver finds assets during bundling (via file extension matching)
  2. Assets are processed (resized, hashed) and placed in the bundle output
  3. At runtime, registerAsset() is called for each asset
  4. 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):

  1. InitializeCore — bootstraps the React Native runtime environment
  2. Polyfills from @react-native/polyfills — fills gaps in the JS engine
  3. Application entry point — the app's index.js or 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:

  1. Serialize JS arguments to JSON
  2. Queue the message on the bridge
  3. Deserialize on the native side
  4. Execute
  5. Serialize the return value
  6. Queue the response
  7. 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 defined if 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 localhost only (not 0.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.lock pins exact dependency versions for reproducible builds
  • Verify lockfile integrity in CI (detect unexpected changes)
  • Audit dependency updates before merging lockfile changes
  • Use yarn audit to 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:

  • .hbc files 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:

  1. JS thread — where React reconciliation runs
  2. Background thread — where tree diffing and clone operations run
  3. 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 as CLIError when metro.config.js cannot 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:

  1. Inspector proxy — multiplexes CDP sessions between devices and debuggers (see Section 5.1)
  2. Debugger launcher — opens the debugger frontend in a browser or Electron shell
  3. 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 ID
  • getAssetByID(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:

  1. Register codegen Gradle tasks (spec file discovery, native code generation)
  2. Configure CMake for C++ native library compilation
  3. Set up Hermes bytecode compilation for release builds
  4. Manage dependency versions across React Native libraries
  5. Configure build variants (debug vs. release behavior differences)
  6. Register test tasks
  7. 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 defined error), and development mode must be disabled (Benchmarks should not be run in development mode error). 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:

  1. Developer makes changes to public APIs
  2. CI runs scripts/js-api/ → generates new TypeScript types → diffs against baseline
  3. CI runs scripts/cxx-api/parser/ → generates new C++ API snapshot → diffs against baseline
  4. Any surface changes require explicit approval
  5. 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.port in metro.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-stack to symbolicate native crashes. On iOS, use Xcode's crash report symbolicator or atos command.

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:

  1. Check if the native module has a version compatible with the new React Native version
  2. Re-run codegen to regenerate native bindings
  3. Check for breaking changes in the React Native changelog
  4. 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:

  1. Verify com.facebook.react plugin version matches the React Native version
  2. Check AGP version compatibility
  3. Clean the Gradle cache: ./gradlew clean
  4. 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 workspaces
  • yarn workspace <name> <command> — runs a command in a specific workspace
  • yarn 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::HostObject are 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::Value references to JS objects
  • These references must be explicitly released when no longer needed
  • jsi::WeakObject provides 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'):

  1. Check if it's a Node.js built-in (rejected — React Native does not include Node built-ins)
  2. Check resolverMainFields in package.json:
    • react-native field (React Native-specific entry point)
    • browser field (browser-compatible entry point)
    • main field (default entry point)
  3. Check platform extensions:
    • some-module.android.js (on Android)
    • some-module.ios.js (on iOS)
    • some-module.js (fallback)
  4. 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