Skip to main content
React Native uses a sophisticated multi-threaded architecture to achieve optimal performance. Understanding this threading model is crucial for building performant applications and debugging issues.

Thread Overview

React Native applications typically use four main threads:

1. JavaScript Thread

Executes all your JavaScript code:
  • React rendering - Component renders and reconciliation
  • State updates - Processing setState and hooks
  • Event handlers - Button presses, input changes, etc.
  • Business logic - App-specific computations
  • Redux/state management - State transitions
  • Async operations - Promise chains, async/await
In the new architecture, this is where JSI enables synchronous calls to native code without thread switching.

2. UI Thread (Main Thread)

The native platform’s main thread:
  • View rendering - Drawing pixels to screen
  • Layout application - Positioning views
  • User input - Touch events, keyboard input
  • Animations - Native animation execution
  • View mutations - Creating, updating, destroying views
  • Platform APIs - iOS UIKit, Android View system calls
Blocking the UI thread causes jank and unresponsive UI. Keep operations under 16ms for 60 FPS.

3. Shadow Thread (Background Thread)

Handles layout computation in Fabric:
  • Yoga layout - Flexbox calculations
  • Shadow tree operations - Cloning, diffing shadow nodes
  • Commit phase - Processing React commits
  • Diffing - Generating mutation lists
Benefits:
  • UI thread stays responsive during layout
  • Complex layouts don’t block user interaction
  • Can compute layout for upcoming screens

4. Native Modules Background Threads

TurboModules can specify thread requirements:
  • Network requests - HTTP calls, downloads
  • Database operations - SQLite queries
  • File I/O - Reading/writing files
  • Image processing - Decoding, resizing
  • Heavy computations - Cryptography, compression

Threading in the New Architecture

JSI and Synchronous Calls

With JSI, JavaScript can call native code synchronously:
C++ implementation:
This executes on the JavaScript thread - no thread switch!

RuntimeExecutor

The RuntimeExecutor safely schedules work on the JavaScript thread from any thread. Defined in ReactCommon/runtimeexecutor/ReactCommon/RuntimeExecutor.h:
Usage pattern:
Key benefits:
  • Thread safety - Runtime access serialized
  • Non-blocking - Posts to queue, doesn’t wait
  • Error handling - Exceptions caught and reported

CallInvoker

TurboModules use CallInvoker for thread management:
Example - calling JavaScript callback from native:

Event Loop Integration

The JavaScript thread implements an event loop aligned with web standards. From ReactCommon/react/renderer/runtimescheduler/__docs__/README.md:

Event Loop Phases

Each tick of the event loop:
  1. Select Task - Choose next task by priority
  2. Execute Task - Run the task’s JavaScript/C++ callback
  3. Process Microtasks - Drain microtask queue (Promises, queueMicrotask)
  4. Update Rendering - Flush UI updates to host platform

Atomicity of UI Updates

Each event loop tick produces one atomic UI update:
Benefits:
  • Predictable - UI updates happen at well-defined points
  • Atomic - No partial updates visible to user
  • Aligned with web - Same semantics as browsers

Task Priorities

RuntimeScheduler supports priority-based scheduling:
Higher priority tasks run first:

Fabric Rendering Pipeline Threading

Phase 1: Render (JavaScript Thread)

Operations:
  • React reconciliation
  • Call Fabric UIManager via JSI
  • Create/clone shadow nodes
  • Build new shadow tree
Thread: JavaScript thread

Phase 2: Commit (Background Thread)

Operations:
  • Run commit hooks
  • Calculate layout (Yoga)
  • Diff shadow trees
  • Generate mutation list
Thread: Shadow thread (background)

Phase 3: Mount (UI Thread)

Operations:
  • Apply mutations to views
  • Create/update/delete native views
  • Set view properties
  • Update layout
Thread: UI thread (main thread)

Thread Coordination

Key point: JavaScript thread doesn’t block waiting for layout or mounting!

TurboModule Threading

Synchronous Methods

Execute on JavaScript thread:
Synchronous TurboModule methods block the JavaScript thread. Keep them fast or users will see frozen UI.

Asynchronous Methods

Can run on any thread:
The promise resolution automatically happens on the JavaScript thread.

Specifying Thread Requirements

iOS - require main thread:
Android - require UI thread:

Animation Threading

JavaScript-Driven Animations

Threading:
  • Animation ticks on JavaScript thread
  • Each tick triggers Fabric render
  • Can drop frames if JS thread busy

Native-Driven Animations

Threading:
  • Animation runs on UI thread
  • Bypasses JavaScript thread entirely
  • Smooth even if JavaScript thread blocked

Animation Backend

From ReactCommon/react/renderer/animationbackend/__docs__/AnimationBackend.md: The Animation Backend allows animation frameworks to update props without going through React:
Threading benefits:
  • Layout animations on shadow thread
  • Non-layout animations on UI thread
  • JavaScript thread not involved

Event Handling Threading

Event Emission

Native to JavaScript:

Event Priorities

From ReactCommon/react/renderer/core/EventEmitter.h:
Examples:
  • Discrete: Press, focus, blur
  • Continuous: Scroll, drag, mouse move
  • AsynchronousBatched: Most custom events

Event Beat

Synchronizes events with rendering:
Ensures events are batched and processed with rendering updates.

Thread Safety Best Practices

1. Never Share JSI Values Across Threads

2. Use RuntimeExecutor for JavaScript Thread Access

3. Protect Shared State with Mutexes

4. Prefer Immutable Data Structures

5. Use Weak Pointers to Avoid Cycles

Debugging Threading Issues

Detect Thread Violations

iOS:
Android:

Thread Sanitizer

Enable ThreadSanitizer to detect races: Xcode:
  1. Edit Scheme
  2. Run tab
  3. Diagnostics
  4. Enable “Thread Sanitizer”
Android:

Logging Thread IDs

Xcode Instruments

  • Time Profiler - See which threads are busy
  • System Trace - Visualize thread activity
  • Thread States - Identify blocked threads

Performance Optimization

Minimize Thread Switching

Batch UI Updates

Offload Heavy Work

Use requestIdleCallback

Runs when JavaScript thread is idle, won’t block user interactions.

Further Reading

Architecture Overview

See how threading fits in the architecture

JavaScript Interface

JSI and thread safety

Fabric Renderer

Fabric’s multi-threaded rendering

TurboModules

Threading in TurboModules