In a bare React Native 0.87 Android build, what do the JDK, Android SDK and Gradle wrapper each provide, and which versions matter?
answer
- three layers: Java, SDK, build tool
- JDK 17 recommended and targeted
- compileSdk 37 in 0.87
- ANDROID_HOME or local.properties
- always ./gradlew, never global gradle
basics
~20 sThe 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 sAn 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 linesexport 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 --versiongo deeper
Recall the three installs: JDK 17, the Android SDK with ANDROID_HOME set, and building through ./gradlew.
Explain what compileSdk, buildTools and minSdk each control in android/build.gradle, how Gradle finds the SDK, and what the wrapper pins.
Tell from the failure which layer broke, keep the wrapper and SDK versions consistent across laptops and CI, and plan SDK bumps with upgrades.
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