skip to content

In a bare React Native 0.87 Android build, what do the JDK, Android SDK and Gradle wrapper each provide, and which versions matter?

level: middleimportance: should knowfreq 42%

answer

  1. three layers: Java, SDK, build tool
  2. JDK 17 recommended and targeted
  3. compileSdk 37 in 0.87
  4. ANDROID_HOME or local.properties
  5. always ./gradlew, never global gradle

basics

~20 s

The JDK runs Gradle and compiles Java and Kotlin (React Native targets Java 17); the Android SDK supplies the platform named by compileSdk (37 in 0.87) plus build tools; the Gradle wrapper pins the Gradle version the project was tested with.

solid answer

~40 s

An Android build of a bare React Native app needs three layers to agree. The **JDK** runs Gradle and compiles Java and Kotlin; the docs recommend JDK 17, and React Native's Gradle plugin sets Java source and target compatibility and the Kotlin JVM toolchain to 17. The **Android SDK**, found through `ANDROID_HOME` or the git-ignored `local.properties`, must contain the platform and build tools that `android/build.gradle` names: in 0.87 `compileSdkVersion = 37` and `buildToolsVersion = "37.0.0"`, with `minSdkVersion = 24`. The **Gradle wrapper**, `android/gradlew` plus `gradle-wrapper.properties`, downloads and runs the exact Gradle version the template pins. Mismatches in any layer fail before your code compiles.

code

bash · 5 lines
bash
export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/platform-tools
cd android && ./gradlew --version

go deeper

for a junior

Recall the three installs: JDK 17, the Android SDK with ANDROID_HOME set, and building through ./gradlew.

for a middle

Explain what compileSdk, buildTools and minSdk each control in android/build.gradle, how Gradle finds the SDK, and what the wrapper pins.

for a senior

Tell from the failure which layer broke, keep the wrapper and SDK versions consistent across laptops and CI, and plan SDK bumps with upgrades.

for a principal

Decide how the team standardises Android toolchains, for example pinned CI images, so an SDK or Gradle bump is one reviewed change.

## Three layers, one build A bare React Native Android build is a Gradle build of the `android/` folder. Three separately installed pieces have to agree: | Layer | What it is | What it provides | React Native 0.87 expectation | |---|---|---|---| | **JDK** | Java Development Kit | runs Gradle, compiles Java and Kotlin | JDK 17 recommended; code compiled for Java 17 | | **Android SDK** | platforms, build tools, emulator | the Android APIs you compile against | platform 37, build tools 37.0.0 | | **Gradle wrapper** | `gradlew` plus a properties file | the exact Gradle version | whatever `gradle-wrapper.properties` pins | ## The JDK The **JDK** is needed because Gradle is a JVM program and the Android sources are Java and Kotlin. React Native's setup guide recommends the **Zulu build of JDK 17** and warns that higher JDK versions may cause problems. React Native's Gradle plugin reinforces this: for every Android application and library module it sets `sourceCompatibility` and `targetCompatibility` to Java 17 and configures the Kotlin plugin's `jvmToolchain(17)`. In practice: - set `JAVA_HOME` to the JDK 17 installation, because that is what `gradlew` uses to start Gradle; - when an IDE and a terminal disagree, check which JDK each one uses before blaming the project. ## The Android SDK The **Android SDK** contains one **platform** per API level, the **build tools**, the platform tools and the emulator. Gradle compiles against the platform that `compileSdkVersion` names, so that platform and the matching build tools must be installed. The template keeps these values in an `ext` block of `android/build.gradle`: - `compileSdkVersion = 37` and `buildToolsVersion = "37.0.0"` in 0.87, raised in that release; - `minSdkVersion = 24`, the oldest Android version the app installs on; - libraries must now compile against at least SDK 34. The versioned setup guide still tells you to install Android 15 (API 35) and build tools 36.0.0; the version your project's `build.gradle` names is what the build actually needs, so install that one through the SDK Manager. Gradle finds the SDK through the **`ANDROID_HOME`** environment variable or through `sdk.dir` in **`android/local.properties`**. The template's `.gitignore` excludes `local.properties`, because the path differs per machine. The setup guide also adds `$ANDROID_HOME/emulator` and `$ANDROID_HOME/platform-tools` to `PATH`. ## The Gradle wrapper The **Gradle wrapper** is a small script, `android/gradlew`, plus `android/gradle/wrapper/gradle-wrapper.properties`, whose `distributionUrl` names an exact Gradle release. The first run downloads that release; every later run uses it. React Native moved to Gradle 9 in 0.82, and each upgrade can bump the wrapper again. Rules that follow: 1. Always build with `./gradlew`, never a globally installed `gradle`, whose version is unrelated to the project. 2. Commit the wrapper files, so every machine and CI job uses the same Gradle. 3. If `npm run android` fails on macOS with `spawnSync ./gradlew EACCES`, the script lost its execute bit; `chmod +x android/gradlew` fixes it. ## How mismatches show up - **Wrong JDK**: Gradle or the Kotlin compiler fails early, before any app code is built. - **Missing SDK platform or build tools**: the build stops asking for the API level or build tools version named in `build.gradle`. - **SDK not found**: Gradle reports no SDK location until `ANDROID_HOME` or `local.properties` is set. - **Global Gradle used**: plugin incompatibilities that disappear with `./gradlew`. Reading which layer failed tells you which installation to fix, and the fix almost never involves JavaScript. ## Keeping laptops and CI aligned The same three layers exist on every CI machine, and most "works on my machine" Android failures are a version drift between them: - **Pin the JDK** in CI to the version the team uses locally, rather than inheriting whatever the runner image ships. - **Install the SDK platform and build tools the project names**, not "latest"; when an upgrade raises `compileSdkVersion`, the CI image changes in the same pull request. - **Never install Gradle separately** on CI; the committed wrapper is the single source of truth. - **Cache Gradle's downloads** between runs, since the wrapper distribution and dependencies are fetched on first use. Written down once, these rules turn a React Native upgrade that raises Android minimums into a checklist instead of a day of red builds.

  • In React Native, why build with ./gradlew instead of a globally installed gradle?
    The wrapper's `gradle-wrapper.properties` pins the Gradle release the project and React Native's Gradle plugin were tested with, and downloads it on first use. A global `gradle` is whatever version happens to be installed, which can be incompatible with the Android Gradle Plugin the project uses.
  • Why is android/local.properties git-ignored in the React Native template?
    It holds machine-specific values, chiefly `sdk.dir`, the path to that developer's Android SDK. Committed, it would point other machines at a path they do not have.
  • A React Native 0.87 library fails to build because it compiles against SDK 33; why?
    React Native 0.87 raised the minimum compile SDK for libraries to 34. A library whose own `compileSdk` is lower has to be updated, or patched to compile against a newer SDK.

saying these in an interview costs you the question

  • Any JDK works; newer is always better for Gradle
  • A globally installed gradle is equivalent to ./gradlew
  • compileSdkVersion decides the oldest Android version the app runs on
  • local.properties should be committed so everyone shares the SDK path
  • The latest SDK installed by Android Studio is always the one the build needs