How the React Native Build System Is Configured: Gradle, CMake, and Android Build Setup

The React Native build system is configured through Kotlin DSL Gradle scripts that orchestrate Android library compilation, CMake-based native builds for C++ dependencies, and Hermes engine integration, centered in build.gradle.kts and packages/react-native/ReactAndroid/build.gradle.kts with customization via Gradle properties and environment variables.

React Native's build system is a hybrid architecture spanning Gradle for Android, Xcode for iOS, and Metro for JavaScript bundling. In the facebook/react-native open-source repository, the Android configuration is the most complex, defined entirely in Kotlin DSL scripts that manage versioning, native compilation, and dependency resolution. This guide examines the actual source files that control the build pipeline.

Global Build Configuration in build.gradle.kts

The root build.gradle.kts serves as the central configuration hub that propagates settings to all sub-projects in the monorepo via Gradle's subprojects and allprojects DSL.

Plugin Management and Versioning

Lines 8-16 apply core Gradle plugins including Android, Kotlin, Nexus publishing, and Ktfmt formatting. The build extracts versioning from ReactAndroid/gradle.properties or appends -SNAPSHOT when isSnapshot=true (lines 41-51), assigning the group ID com.facebook.react.

Hermes Engine Substitution

The hermesSubstitution block (lines 14-74) conditionally replaces the local :packages:react-native:ReactAndroid:hermes-engine project with pre-built Maven artifacts. This supports three modes: stable releases, nightly builds, or source compilation, controlled by Gradle properties like react.internal.useHermesStable.

Cleaning and Publishing Tasks

The custom clean task (lines 68-98) extends beyond standard Gradle cleaning to remove generated C++ builds, downloaded third-party artifacts, and temporary files. Maven Central publishing configures Sonatype credentials read from environment variables or Gradle properties (lines 52-56), while nexusPublishing (lines 57-69) and the publishAllToMavenTempLocal task handle artifact distribution.

Android Module Configuration in ReactAndroid/build.gradle.kts

The ReactAndroid module contains the core Android library build logic, handling native C++ compilation through CMake and third-party dependency management.

Native Build and CMake Integration

The externalNativeBuild block (lines 70-82) invokes CMake to compile three critical native libraries: reactnative, jsi, and hermestooling. CMake arguments point to ReactCommon, specify the Android STL, toolchain, and conditionally enable Hermes flags. The actual CMake project resides in packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt.

Third-Party Dependency Downloads

Tasks defined between lines 96-165 use the de.undercouch.gradle.tasks.download.Download plugin to fetch and extract Boost, double-conversion, Folly, FastFloat, fmt, and glog into the third-party-ndk directory. These tasks execute before native compilation to ensure headers and libraries are present.

Architecture Filters and Build Variants

ABI filters default to armeabi-v7a,x86,x86_64,arm64-v8a via the reactNativeArchitectures() function (lines 93-94), customizable through the REACT_NATIVE_ARCHITECTURES Gradle property. The custom debugOptimized build type (lines 72-79) compiles native code with -DCMAKE_BUILD_TYPE=Release while maintaining Java/Kotlin debug configurations.

Codegen and Prefab Publishing

The buildCodegenCLI task (lines 53-67) executes JavaScript-to-Java/Kotlin code generation before any native build, ensuring bridge code artifacts exist. Prefab publishing (lines 154-158) exposes C++ headers and pre-compiled libraries via prefab { create("jsi") ... }, allowing downstream Android consumers to link against React Native's native interfaces directly from the AAR.

Dependency Configuration

The module declares dependencies on AndroidX, FBJNI, Fresco, SoLoader, Yoga, and OkHttp (lines 88-114). The Hermes engine is declared as a compileOnly dependency, enabling the substitution logic defined in the root project.

Key Configuration Files and Customization Points

Path Purpose
gradle.properties (root) Defines versions for Boost, Folly, Glog, and toggles like hermesV1Enabled
packages/react-native/ReactAndroid/gradle.properties Supplies VERSION_NAME and binary-compatibility validator settings
packages/react-native/ReactAndroid/hermes-engine/build.gradle.kts Builds the Hermes JavaScript engine from source when not substituted
packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt CMake script compiling native libraries (reactnative, jsi, hermestooling)
packages/react-native/ReactAndroid/publish.gradle Maven publishing configuration applied to the module
scripts/releases/ Release automation scripts (e.g., set-version) manipulating version numbers

Common Build Commands and Workflows

Standard Build Operations


# Clean all generated artifacts, native builds, and downloaded dependencies

./gradlew clean

# Build the Android AAR in debug mode

./gradlew :packages:react-native:ReactAndroid:assembleDebug

# Build release version with pre-built Hermes from Maven Central

./gradlew -Preact.internal.useHermesStable=true \
          :packages:react-native:ReactAndroid:assembleRelease

Advanced Configuration


# Specify custom NDK path (useful for CI on Apple Silicon)

./gradlew -PndkPath=/opt/android/ndk/25.1.8937393 assembleDebug

# Build debugOptimized variant (optimized native code, debuggable Java)

./gradlew :packages:react-native:ReactAndroid:assembleDebugOptimized

# Publish to temporary local Maven repository for consumer testing

./gradlew publishAllToMavenTempLocal

Environment Variables and Properties

  • REACT_NATIVE_DOWNLOADS_DIR: Specifies custom directory for third-party C++ dependency downloads
  • REACT_NATIVE_ARCHITECTURES: Comma-separated list of ABIs to build (e.g., arm64-v8a,x86_64)
  • ndkPath: Gradle property pointing to Android NDK installation, consumed in build.gradle.kts (lines 52-56)

Summary

  • The React Native build system relies on Kotlin DSL Gradle scripts defined in the facebook/react-native repository to configure Android artifacts
  • Root build.gradle.kts manages global plugins, versioning, Hermes substitution, and Maven publishing to Sonatype
  • ReactAndroid/build.gradle.kts handles Android library compilation, CMake native builds, third-party C++ dependency downloads, and Prefab publishing for jsi
  • Native compilation occurs through CMake configured in ReactAndroid/src/main/jni/CMakeLists.txt, producing libraries for the JNI bridge and Hermes tooling
  • Customization is achieved through Gradle properties (ndkPath, reactNativeArchitectures) and environment variables controlling download directories and build targets
  • Hermes flexibility allows switching between source builds and pre-built Maven artifacts (stable or nightly) via the root project's substitution mechanism

Frequently Asked Questions

How do I customize the NDK path in React Native's build system?

Pass the ndkPath property when running Gradle tasks: ./gradlew -PndkPath=/opt/android/ndk/25.1.8937393 assembleDebug. The build script reads this value in build.gradle.kts (lines 52-56) and configures the Android Gradle Plugin accordingly. You can also set this in gradle.properties or as an environment variable for CI environments.

What is the debugOptimized build type and when should I use it?

The debugOptimized variant (defined in ReactAndroid/build.gradle.kts lines 72-79) compiles native C++ code with -DCMAKE_BUILD_TYPE=Release flags while keeping Java/Kotlin bytecode in debug mode. Use this when you need to debug Java code but want near-release performance from native modules, as standard debug builds use unoptimized native code that runs significantly slower.

How does the build system handle third-party C++ dependencies like Boost and Folly?

The ReactAndroid/build.gradle.kts defines explicit download tasks (lines 96-165) using the de.undercouch.gradle.tasks.download plugin. These tasks fetch versioned archives from remote repositories, verify checksums, and extract them into third-party-ndk. The CMake configuration in ReactAndroid/src/main/jni/CMakeLists.txt then references these extracted headers and libraries during compilation.

Can I use a pre-built Hermes engine instead of compiling from source?

Yes. The root build.gradle.kts implements a hermesSubstitution block (lines 14-74) that replaces the local :packages:react-native:ReactAndroid:hermes-engine project with Maven artifacts. Pass -Preact.internal.useHermesStable=true for stable releases or -Preact.internal.useHermesNightly=true for nightly builds. When enabled, the build declares Hermes as a compileOnly dependency in ReactAndroid/build.gradle.kts (lines 88-114) and downloads pre-built binaries from Maven Central instead of compiling local source.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →