skip to content

Faster Compiles

Native builds dominate a React Native dev loop; prebuilt iOS core binaries, ccache, Gradle configuration caching and one-ABI debug builds cut them. Interviewers ask how to speed up a slow local build.

part ofReact Nativeoverview, primer and where to startread it →
on this pageshow

explore

questions

4

In a React Native Android project, what does the reactNativeArchitectures Gradle property control, and why build one ABI during development?

level: juniorimportance: should knowfreq 35%

answer

  1. four ABIs by default
  2. native code compiled once per ABI
  3. --active-arch-only picks the device's
  4. -PreactNativeArchitectures=arm64-v8a
  5. never ship a one-ABI release

basics

~20 s

reactNativeArchitectures lists the Android ABIs whose native code gets compiled and packaged, by default all four. Building only the ABI of your emulator or phone during development cuts native build time sharply; release builds must keep every ABI.

solid answer

~40 s

Android native code is compiled separately for each ABI — `armeabi-v7a`, `arm64-v8a`, `x86` and `x86_64` — and a React Native app builds all four by default. `reactNativeArchitectures` in `android/gradle.properties` narrows that list; the React Native Gradle plugin turns it into the NDK's ABI filters. During development I only need the ABI of the device in front of me, so I run `npx react-native run-android --active-arch-only`, which detects it, or pass `-PreactNativeArchitectures=arm64-v8a` to Gradle; Expo's `npx expo run:android` already does this for debug builds. The React Native docs estimate about a 75% cut in native build time. The catch: a build limited to one ABI will not run on devices of another, so release builds must go back to all four.

code

bash · 8 lines
bash
# Community CLI: detect and build only the connected device's ABI
npx react-native run-android --active-arch-only

# Plain Gradle: choose the ABI explicitly
cd android && ./gradlew :app:assembleDebug -PreactNativeArchitectures=arm64-v8a

# Expo: active ABI is the default for debug builds; opt out with
npx expo run:android --all-arch

go deeper

for a junior

Remember that Android builds native code once per ABI, that React Native builds four by default, and that --active-arch-only builds just the device's.

for a middle

Explain how the Gradle plugin turns reactNativeArchitectures into ABI filters, the ways to set it, and why a one-ABI build fails on other devices.

for a senior

Show how you keep one-ABI builds out of release and CI artefacts while giving every developer the fast path by default.

for a principal

Weigh which ABIs the product still supports, what dropping 32-bit ARM would save in build and app size, and who decides that.

## What an ABI is and why it multiplies build time An **ABI** (Application Binary Interface) is the combination of CPU architecture and calling conventions that compiled native code targets. Android supports four that matter for React Native apps: | ABI | Typical device | |---|---| | `arm64-v8a` | nearly all current phones; emulators on Apple silicon Macs | | `armeabi-v7a` | older 32-bit ARM phones | | `x86_64` | emulators on Intel and AMD hosts | | `x86` | old 32-bit emulators | Every piece of **C++** in the build — the app's own CMake targets, code generated for New Architecture libraries, native modules that ship C++ — is compiled **once per ABI**. Building all four means compiling the same sources four times. The React Native docs put the saving from building a single ABI at roughly **75% of native build time**. ## How React Native exposes the setting `reactNativeArchitectures` is a Gradle property read by the React Native Gradle plugin. The plugin turns the comma-separated list into the NDK's ABI filters (unless you have enabled Android's ABI splits, which are not compatible with filters), so only those ABIs are compiled and packaged. Ways to set it: 1. **Per run, automatically** — `npx react-native run-android --active-arch-only` detects the ABI of the running emulator or connected phone and prints something like `info Detected architectures arm64-v8a`. 2. **Per run, explicitly** — `./gradlew :app:assembleDebug -PreactNativeArchitectures=arm64-v8a`. 3. **Per machine or project** — `reactNativeArchitectures=arm64-v8a` in `android/gradle.properties` (the template lists all four there). 4. **In Expo projects** — `npx expo run:android` builds only the connected device's ABI for debug builds by default; `--all-arch` turns that off. ## Knowing which ABI to build - **A connected phone** is almost always `arm64-v8a`; `adb shell getprop ro.product.cpu.abi` prints the primary ABI of any connected device or emulator. - **An emulator** matches its system image — `x86_64` images on Intel and AMD hosts, `arm64-v8a` images on Apple silicon. - **Checking the result:** the Community CLI prints the detected list, and an APK is a zip archive whose `lib/` folder has one subfolder per packaged ABI, so listing it shows what you actually built. ## Why it is safe in development and unsafe in release A build with one ABI contains native libraries for that ABI only. Installed on a device with a different ABI, the app cannot load its native code — it fails to install or crashes at start. That is fine on your own phone, and exactly wrong for users: - **Development:** build only the ABI of the device you are using. - **Release:** remove the override so the app bundle contains every ABI your users need. The docs explicitly warn to remove these flags before building a release. - **Shared `gradle.properties`:** if you commit a one-ABI value, every teammate and CI job inherits it — prefer command-line flags or an uncommitted local override. ## A team setup that works 1. **Commit the full list** — all four ABIs — in the project's `android/gradle.properties`, so CI and release builds are complete by default. 2. **Give developers the fast path** through the command line: `--active-arch-only` in the run script, or Expo's default active-ABI behaviour. 3. **Allow personal overrides** in the user-level `~/.gradle/gradle.properties`, which Gradle reads with higher precedence than the project file and which never reaches the repository. ## Where it fits among other build-time levers Single-ABI builds shrink the **amount of C++ compiled**. Other levers attack different costs: - **Gradle configuration cache** (`org.gradle.configuration-cache=true`, supported since React Native 0.79) skips re-evaluating build scripts on repeat builds. - **ccache** reuses compiled objects across clean builds; React Native's Android CMake setup uses it automatically when it is installed. - **A Maven mirror** (`exclusiveEnterpriseRepository`) speeds up dependency downloads. They stack: a one-ABI debug build with ccache and the configuration cache is the fastest local Android loop. ## Common mistakes - Shipping a release built with a one-ABI override — it installs on the developer's phone and fails on others. - Building `x86` and `x86_64` for a physical ARM phone, or `arm64-v8a` only for an Intel-host emulator. - Expecting the setting to speed up Kotlin or Java compilation — it only affects native code. - Forgetting that Expo already does this for debug runs and adding conflicting overrides.

  • What does enabling Gradle's configuration cache add on top of a one-ABI React Native build?
    It attacks a different cost. Every Gradle build first evaluates all build scripts in a configuration phase; with `org.gradle.configuration-cache=true` in `android/gradle.properties`, supported since React Native 0.79, repeat builds reuse that result and go straight to executing tasks. It helps most when you rebuild native code often.
  • A teammate committed reactNativeArchitectures=arm64-v8a to gradle.properties. What can go wrong?
    Every build that reads that file — other developers, CI, possibly release — now packages only `arm64-v8a`. Intel-host emulators need `x86_64` and will fail to run the app, and a release built this way excludes 32-bit ARM devices. Keep one-ABI builds to command-line flags or local, uncommitted overrides.

saying these in an interview costs you the question

  • reactNativeArchitectures also speeds up Kotlin and Java compilation
  • A one-ABI build runs on every Android device, only slower
  • Keep the one-ABI setting in release builds to shrink the app
  • Emulators always need x86 whatever the host machine
  • Expo projects must set reactNativeArchitectures by hand for debug runs
open as a page

How do you enable ccache for a React Native app on Android and on iOS, and how do you confirm it is actually working?

level: middleimportance: should knowfreq 28%

basics

~20 s

Install ccache; React Native's Android CMake setup uses it automatically, and on iOS you turn on ccache_enabled in the Podfile's react_native_post_install (or run pod install with USE_CCACHE=1). Confirm with ccache -s: a second clean build should show mostly hits.

open as a page

How do React Native's precompiled iOS binaries speed up builds since 0.84, and when would you set RCT_USE_PREBUILT_RNCORE=0?

level: middleimportance: should knowfreq 32%

basics

~20 s

Since 0.84, pod install downloads React Native core and its dependencies as precompiled xcframeworks, so clean iOS builds skip compiling them. Set RCT_USE_PREBUILT_RNCORE=0 to build core from source, for example to patch it or opt out of Hermes V1.

open as a page

A two-platform React Native social app's CI build takes 25 minutes; which React Native build settings would you change to cut it, and in what order?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Measure which platform and phase dominate first. Then make sure iOS uses the prebuilt core, split Android test builds by ABI with reactNativeArchitectures, enable Gradle's configuration cache, point downloads at a Maven mirror, and add ccache or sccache where native compilation remains.

open as a page