Here you go โ a clean, structured, publish-ready MDX article based on everything you wrote. I formatted it like a real technical guide (clear sections, code blocks, notes, warnings, tables, etc.).
๐ ๏ธ Full Guide: Setting Up a Complete Expo / Android Build Environment on WSL2 (Ubuntu 24.04)
If you want to perform EAS local builds, Android native builds, or Maestro / bundletool automation inside WSL2, this guide gives you a fully reproducible setup identical to production CI workers.
This article covers:
- Base Linux dependencies
- Node 20.19.4 + npm 10.9.3
- Yarn / pnpm / Bun
- Java 17
- Android SDK + Build-tools + NDK r27b
- Expo / EAS CLI
- Environment variables
- Build verification
โ 0) System Overview (Target Configuration)
| Component | Version | | --------------- | ------------------------------------ | | OS | Ubuntu 24.04 (inside WSL2) | | Node.js | 20.19.4 | | npm | 10.9.3 | | Java | OpenJDK 17 | | Build-tools | 35.0.0 (plus 29.0.3 for compat) | | NDK | 27.1.12297006 (NDK r27b) | | Extras | Yarn, pnpm, Bun, Maestro, bundletool |
Environment variables configured:
JAVA_HOME
ANDROID_HOME
ANDROID_SDK_ROOT
ANDROID_NDK_HOME
EXPO_TOKEN
GRADLE_OPTS
PATH
๐ 1) Install Essential Packages
sudo apt update
sudo apt install -y \
build-essential git unzip zip curl wget ca-certificates \
openjdk-17-jdk
โก 2) Install Node 20.19.4 (CI-Compatible)
Install NVM
export NVM_DIR="$HOME/.nvm"
if [ ! -d "$NVM_DIR" ]; then
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
fi
source "$NVM_DIR/nvm.sh"
Install Node & npm
nvm install 20.19.4
nvm alias default 20.19.4
node -v # v20.19.4
npm -v # 10.9.3
Extra package managers
npm i -g yarn@1.22.22 pnpm@10.14.0 bun@1.2.20
๐ฑ 3) Install Android SDK + Build Plugins + NDK
Create SDK directory
export ANDROID_HOME="$HOME/Android/Sdk"
mkdir -p "$ANDROID_HOME"
Install latest Android command-line tools
cd /tmp
wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O cmdtools.zip
mkdir -p "$ANDROID_HOME/cmdline-tools"
unzip -q cmdtools.zip -d "$ANDROID_HOME/cmdline-tools"
mv "$ANDROID_HOME/cmdline-tools/cmdline-tools" "$ANDROID_HOME/cmdline-tools/tools"
Update PATH temporarily
export PATH="$ANDROID_HOME/cmdline-tools/tools/bin:$ANDROID_HOME/platform-tools:$PATH"
Accept all licenses
yes | sdkmanager --licenses
Install required components
sdkmanager \
"platform-tools" \
"platforms;android-35" \
"build-tools;35.0.0" \
"build-tools;29.0.3" \
"ndk;27.1.12297006" \
"extras;google;m2repository" \
"extras;android;m2repository"
Set NDK path
export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/27.1.12297006"
โ 4) Java & Gradle Configuration
export JAVA_HOME="/usr/lib/jvm/java-17-openjdk-amd64"
export GRADLE_OPTS='-Dorg.gradle.jvmargs="-XX:MaxMetaspaceSize=1g -Xmx4g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8" -Dorg.gradle.parallel=true -Dorg.gradle.daemon=false'
๐ฆ 5) Install Expo & EAS Tools
npm i -g eas-cli expo-cli
Optional Tools
Maestro
curl -Ls "https://get.maestro.mobile.dev" | bash
Bundletool
sudo mkdir -p /opt/bundletool
sudo wget -q https://github.com/google/bundletool/releases/download/1.17.2/bundletool-all-1.17.2.jar \
-O /opt/bundletool/bundletool.jar
echo 'export PATH="/opt/bundletool:$PATH"' >> ~/.bashrc
echo 'alias bundletool="java -jar /opt/bundletool/bundletool.jar"' >> ~/.bashrc
๐ง 6) Persistent Environment Variables (~/.bashrc)
Append this to ~/.bashrc
# Android SDK
export ANDROID_HOME="$HOME/Android/Sdk"
export ANDROID_SDK_ROOT="$ANDROID_HOME"
export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/27.1.12297006"
export PATH="$HOME/.nvm/versions/node/v20.19.4/bin:/opt/bundletool:$ANDROID_HOME/build-tools/29.0.3:$ANDROID_HOME/build-tools/35.0.0:$ANDROID_NDK_HOME:$ANDROID_HOME/cmdline-tools/tools/bin:$ANDROID_HOME/platform-tools:$PATH"
# Java
export JAVA_HOME="/usr/lib/jvm/java-17-openjdk-amd64"
# Expo (replace with your actual token)
export EXPO_TOKEN="<your-expo-token>"
# Gradle settings
export GRADLE_OPTS='-Dorg.gradle.jvmargs="-XX:MaxMetaspaceSize=1g -Xmx4g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8" -Dorg.gradle.parallel=true -Dorg.gradle.daemon=false'
# Optional CI-like mode
export CI=1
Apply changes:
source ~/.bashrc
and since we are using WSL2, we need to save also in ~/.profile
nano ~/.profile
add in the bottom the following
if [ -f "$HOME/.bashrc" ]; then
source "$HOME/.bashrc"
fi
๐งช 7) Validate Everything
node -v
npm -v
java -version
sdkmanager --list | head -n 50
echo $ANDROID_HOME
echo $ANDROID_NDK_HOME
bundletool --version
maestro --version
Sanity check folders:
ls "$ANDROID_HOME"
ls "$ANDROID_NDK_HOME"
๐ 8) Test a Local EAS Build
Inside an Expo project:
npx eas build --local --platform android --profile production
If everything is correct, the build will start without any Android or Java errors.
If an error for expo auth happened
then we should use auth through cli not with token
unset EXPO_TOKEN
npx eas login
๐ Conclusion
You now have a 100% complete Expo Android build environment inside WSL2 Ubuntu 24.04, fully compatible with:
- EAS local builds
- React Native CLI builds
- Gradle tasks
- Maestro automation
- Bundletool / APK / AAB manipulation
- NDK-based native modules
This matches the same versions used by many CI runners, so your local builds will behave exactly the same.
If you want, I can also prepare:
โ A script to install ALL of this automatically โ A version for macOS โ A version for native Windows (no WSL) โ A Docker image for reproducible Android builds
Just tell me!
Read more
Next.js App on a VPS (Hetzner) in traditional way
Clone your repo, install Node, build your Next.js app, run it on a custom port, and keep it alive with PM2.
How to Enable the Classic Android Navigation Bar in BlueStacks 5 (Back / Home / Recents)
Enable the classic Android navigation bar (Back, Home, and Recent buttons) in BlueStacks 5 by editing a hidden configuration file. Step-by-step guide for developers and testers.
Domain name and HTTPS on Ubuntu VPS with Nginx
Register a domain on Namecheap, point it to your VPS, configure Nginx with sites-available/sites-enabled, and secure it with free SSL using Certbot.
