emulatorsh
v0.1.8
Published
Launching Android emulators and iOS simulators from the shell, for humans.
Maintainers
Readme
>_ emulatorsh📱 ·

Interactive terminal UI to list, create, and launch Android Virtual Devices and iOS Simulators. The CLI command is emulatorsh from the shell. Or import emulatorsh; in your code and use it as an SDK! 🤓

Pick a platform, pick a device, and boom! You have your emulator up and running. The Emulator process starts detached so you can safely close the terminal if you wish. You're missing an Android SDK? No problem, you can do it right from the console! On Android you can also install system images and create new AVDs without opening Android Studio. There's no typing, no need to copy or remember PIDs or device names, the console is interactive. You simply navigate with your keyboard. Yup... I know, I'm excited too!
Licensed under MIT.
But why, Chris?
I got tired of opening Android Studio just to boot a Pixel. 😫 I wanted a convenient IDE agnostic way that's actually made for humans. 😊
Creating an AVD meant clicking through Device Manager, waiting on a system image, then discovering the hardware keyboard was off — so every login screen, every text field, I was poking at a fake on-screen keyboard. Why is that hard? Why is this keyboard menu moving on every major Android version? Turning hw.keyboard=yes and hunting config.ini by hand ends up being the only working option on new devices. Doing that once is annoying. Doing it every time I needed a clean API level or a Wear device was a waste of an afternoon.
The Android Studio meanwhile kept changing how emulators launch. Sometimes the window is its own process. Sometimes it boots inside the IDE and I still don't fully know why — a setting, a toolbar button, a new Device Manager. I just wanted a device running so I could run tests, not debug the IDE.
iOS is not innocent either. xcrun simctl works, if you enjoy UDIDs. I was already in a terminal. I did not want to leave it. I'm only human after all, dear Apple, don't put the blame on me...
So I wrapped the tools I already had — emulator, avdmanager, sdkmanager, simctl — in a single interactive keyboard UI. Pick a platform, pick a device, it starts detached so closing the terminal does not kill the emulator. New Android devices get a hardware keyboard without me opening an ini file. Running devices are marked so I do not boot a second copy by mistake.
This is the tool I wished I had on the days I lost an hour to Device Manager. If you have lived that, it is for you too.
No runtime npm dependencies. It shells out to the SDK and Xcode on your machine.
What it does
Asks Android, iOS, or watchOS, each with
[running: n/total]indicator.iOS / watchOS — lists available simulators from
xcrun simctlfor that runtime. Booted devices are marked green[running]. Selecting one boots it and opens the Simulator app.Android — lists AVDs from
emulator -list-avds. Running AVDs are marked green[running]. Selecting one starts it detached. The last row is purple Create new device.On a device list,
ccloses the highlighted running device: Back returns to the list; Suspend or Terminate runs the command and exits (or returns to the platform list with--sticky). Android Suspend is a gracefuladb emu killso Quick Boot can save a snapshot (next start is not a cold boot). Terminate force-kills the emulator and deletes that AVD’s Quick Boot snapshots so the next start is a cold boot — installed apps and userdata stay; it is not a wipe. iOS and watchOS only offer Suspend (simctl shutdown— it keeps the simulator disk, like a soft shutdown). In--simulate, that updatesdb/demo.dband closes the fake window if it is still open.
You like it headless? Not an issue! Explore the emulatorsh SDK and use it directly inside your project
Same tricks, no keyboard. Drop emulatorsh into a Node project and drive Android, iOS, and watchOS from TypeScript or JavaScript — list, launch, create, install, suspend, terminate. Starts detached, same as the CLI. Needs the same Android SDK / Xcode setup as Environment below.
npm install emulatorshThe default import talks to your machine:
import emulatorsh from "emulatorsh";
emulatorsh.android.start("Pixel_9_API_36");start takes a device from list(), or a string — AVD name on Android, UDID or simulator name on iOS / watchOS.
Learn more in the SDK guide — launch, create, install, and a sandbox for tests.
Create a new Android device
- Form factor: Mobile Phone or Wear.
- Installed system image (or purple Install new SDK).
- Device profile, shown as
Pixel_9_Pro_API_36for the selected SDK. Already-created copies show[installed: n]. - Creates the AVD with
avdmanager, enableshw.keyboard=yes, and starts it.
If no Wear or phone system image is installed, the SDK list shows orange No SDK installed plus Install new SDK.
Installing an SDK skips the SDK list and opens the device list for that image. Escape from devices returns to the SDK list with the new image selected. Selecting an already-installed SDK in the install list does nothing (returns to the list).
Install
npm install -g emulatorsh
emulatorsh
emulatorsh --sticky # stay on the platform list after start / create / closeRequires Node.js 18+. But let's be real, use Node.js 22.5+ don't be a dino! 🦖
A global install only puts emulatorsh on your PATH. No install scripts, no runtime npm dependencies, nothing phones home — it shells out to the Android / Xcode tools already on your machine. Tagged releases on the npm page show a Provenance check: that tarball was built from this repo on GitHub Actions.
Environment
The CLI does not install Android Studio or Xcode. It shells out to tools that must already be on the machine.
Android
Set one of these (first existing directory wins):
| Variable | Role |
| --- | --- |
| ANDROID_SDK_ROOT | Preferred SDK root |
| ANDROID_HOME | Fallback SDK root |
| ANDROID_AVD_HOME | Optional AVD directory (default ~/.android/avd) |
If those env vars are unset, the CLI also looks at:
~/Library/Android/sdk(macOS Android Studio default)~/Android/Sdk(Linux default)- then infers the root from a found
emulatorbinary
Required binaries (resolved under the SDK root, then PATH):
| Tool | Typical path |
| --- | --- |
| emulator | $SDK/emulator/emulator |
| adb | $SDK/platform-tools/adb |
| avdmanager | $SDK/cmdline-tools/latest/bin/avdmanager |
| sdkmanager | $SDK/cmdline-tools/latest/bin/sdkmanager |
avdmanager / sdkmanager are also searched in other cmdline-tools/<version>/bin folders and the legacy $SDK/tools/bin location.
Minimum Android setup
- Android Studio or a standalone command-line tools install.
- SDK Command-line Tools, Platform-Tools, and Emulator packages.
- At least one system image if you want to create devices from the CLI (
sdkmanageror Android Studio SDK Manager). - Accept licenses:
sdkmanager --licenses.
Example ~/.zshrc:
export ANDROID_HOME="$HOME/Library/Android/sdk"
export ANDROID_SDK_ROOT="$ANDROID_HOME"
export PATH="$ANDROID_HOME/emulator:$ANDROID_HOME/platform-tools:$ANDROID_HOME/cmdline-tools/latest/bin:$PATH"System images are filtered to the host ABI: arm64-v8a on Apple Silicon, x86_64 otherwise. Wear images use tags matching wear (for example android-wear, android-wear-signed), not phone google_apis_playstore. China-only Wear tags (*-cn) are skipped.
Android emulator stdout/stderr go to /tmp/emulator.log.
iOS (macOS only)
- Xcode from the Mac App Store.
- Open Xcode once and install additional platforms if prompted.
xcrun simctlmust work (xcode-selectpointing at Xcode).
Devices come from xcrun simctl list devices available -j. iOS shows iOS-<major> / iOS-<major>-<minor> runtimes. watchOS shows watchOS-* the same way (Apple Watch simulators). tvOS and visionOS are not listed. Starting a simulator runs simctl boot <udid> and open -a Simulator.
There is no “create simulator” flow: Apple devices are Xcode runtime definitions, not AVDs.
Keyboard
| Key | Action |
| --- | --- |
| ↑ ↓ or k j | Move |
| ← → or h l | Move between columns (when the list is two-column) |
| Enter | Select |
| Escape | Back one step |
| c | Close the selected running device (suspend or terminate) |
| q or Ctrl+C | Quit CLI |
Lists with more than 8 items use two columns when the terminal is at least 72 characters wide. Long lists paginate (20 items per page). The footer shows 2/5 ↓ more.
Needs an interactive TTY. Piped or non-TTY stdin/stdout will exit with an error.
Wanna play safely?
No SDK, no Xcode, no problem. --simulate is a playground for the whole CLI — same menus, same keys — so you can try listing, creating, installing, launching, and closing without touching a real emulator or any of the tools those flows normally need.
To run in simulation mode:
emulatorsh --simulateYou made too much mess in your playground? Nuke it and start over ;)
emulatorsh --simulate-clear--simulate looks exactly like a real run. In --simulate, emulatorsh makes no calls to adb / emulator / sdkmanager / avdmanager / simctl (and the SDK/AVD files those tools already own).
With --simulate, those CLIs are mocked and persist into a virtual playground state. It is juat a sandbox demo machine with fake emulators, nothing you do there is about to impact an actual system. --simulate needs Node.js 22.5+ (node:sqlite). The live command still runs on Node 18.
Want to send a fix or a feature? See Contributing. Hacking or cutting a release? See Development.
