5.6 KiB
Development with Nix (Android/Expo)
This repo ships a Nix flake that provides reproducible dev shells for React Native + Expo and Android workflows. You don’t need global installs of Node/Watchman/Android SDK—the shell provides everything.
Prereqs
- Nix with flakes enabled (
nix --versionshould work) - (Optional, recommended)
direnv+nix-direnvto auto-enter shells
Shell variants
We publish three dev shells:
default– minimal JS toolchain you always want (Node, pnpm, watchman, git, jq, just)android-local– adds a full Android SDK + Emulator + API 36 Google Play x86_64 system image Good when you run the emulator on your machine.android-remote– no emulator/image; adds adb + scrcpy Good when you run an emulator on a remote server and mirror/control it locally.
Pick one per your setup.
Quick start
A) One-off use (no direnv)
# Minimal JS shell
nix develop .#default
# Local emulator workflow (SDK + emulator + API 36 image)
nix develop .#android-local
# Remote emulator workflow (adb + scrcpy only)
nix develop .#android-remote
B) Auto-enter with direnv (recommended)
Create .envrc at the project root:
# choose one:
use flake .#android-local
# use flake .#android-remote
# use flake .#default
Then:
direnv allow
Any new shell in this folder will enter the selected dev shell automatically.
What the shell sets up
- Node/PNPM/Watchman/Git/JQ/Just (all shells)
- ANDROID_SDK_ROOT / ANDROID_HOME (in
android-local; points to the immutable SDK built by Nix) - adb / emulator / sdkmanager / avdmanager (in
android-local) - adb / scrcpy (in
android-remote)
Tip: we keep the Android SDK fully immutable (declarative). You don’t “install packages” via Android Studio; the flake lists exactly which components are present.
Local emulator workflow (android-local)
- Enter the shell:
nix develop .#android-local
- (First time) Create an AVD for API 36 (Google Play, x86_64):
avdmanager create avd -n a36-play-x86_64 \
-k "system-images;android-36;google_apis_playstore;x86_64"
- Run the emulator:
# GUI window (desktop)
emulator @a36-play-x86_64
# Headless (CI/servers):
emulator @a36-play-x86_64 -no-window -no-audio
# If no KVM: add -gpu swiftshader_indirect
- Verify
adbsees it:
adb devices
- Run your typical Expo/RN commands (Metro, build, etc.) inside the shell.
macOS users: You can still build Android in this shell. The
android-localshell providesplatform-tools+ SDK commands; the GUI Android Studio app is optional. If you prefer to use the macOS GUI emulator instead of the Nix one, that’s fine—usedefaultorandroid-remoteand keep your local Android Studio install.
Remote emulator workflow (android-remote)
Use this when your emulator runs on a remote Linux box (often headless/KVM).
- Enter the shell:
nix develop .#android-remote
- SSH-tunnel the remote adb server back to your machine:
ssh -N -L 5037:127.0.0.1:5037 user@remote-host
- Point
adbat the forwarded server and verify:
adb -H 127.0.0.1 -P 5037 devices
- Mirror/control the remote emulator window locally:
scrcpy
That’s it—everything flows through SSH, and you don’t need any extra ports.
Common tasks
-
Check versions:
adb version sdkmanager --version avdmanager --help -
Upgrade/change Android components Edit the system image or build-tools/platforms listed in
flake.nixunder theandroidSdk36definition, then re-enter the shell. -
Clean emulators/AVDs AVDs live in
~/.android/avdby default. You can remove an AVD with:avdmanager delete avd -n a36-play-x86_64
Troubleshooting
-
Emulator is very slow / won’t start (Linux): Ensure
/dev/kvmexists and your user has permission (kvmgroup). Headless servers without KVM can still run, but add-gpu swiftshader_indirectand expect reduced performance. -
adbdoesn’t see the emulator: Kill any stray local adb server and retry:adb kill-server adb start-server adb devices -
Gradle/Java mismatch: If your Android Gradle Plugin complains about Java, pin the JDK you need in the dev shell and set
JAVA_HOME. (You can add a JDK todefaultPkgsin the flake if your project requires a specific version.) -
Expo/Metro can’t find Android SDK: Confirm
echo $ANDROID_SDK_ROOTprints a path in theandroid-localshell.
CI usage
You can build/test in CI with:
nix develop --command bash -lc 'pnpm install && pnpm test'
or pick a specific shell:
nix develop .#android-local --command bash -lc 'just android-build'
If you want, I can add a tiny Justfile with just avd-create, just avd-run,
and just adb-tunnel-remote helpers so the common commands are one-liners.
Enable Nix flakes globally
If you see errors like:
error: experimental Nix feature 'nix-command' is disabled; add '--extra-experimental-features nix-command' to enable it
…it means flakes are not enabled in your Nix configuration yet.
You can enable them permanently with a one-liner:
sudo mkdir -p /etc/nix && echo 'experimental-features = nix-command flakes' | sudo tee /etc/nix/nix.conf
Then restart your shell (or nix-daemon on macOS), and the error goes away.
From now on you can just run:
nix develop .#android-local
without passing any extra flags.