npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

local-expo-build

v1.1.3

Published

One-stop CLI for local Expo builds. Android (stable) → AAB/APK with EAS-synced versionCode and managed signing. iOS (experimental, macOS) → IPA via xcodebuild with auto export-options.plist.

Readme

local-expo-build

Build signed Expo Android apps on your own machine. Windows, macOS, and Linux supported.

npm version npm downloads license Node.js

local-expo-build turns an Expo project into a signed Android APK or AAB without waiting for an EAS cloud build. It handles Expo prebuild, Gradle compatibility, versioning, release signing, and artifact discovery in one repeatable workflow.

Android is stable. Local iOS IPA builds are experimental and require macOS.

Why use it?

  • Build locally on Windows, macOS, or Linux.
  • Produce a signed AAB for Google Play or a signed APK for direct installation.
  • Keep control of your keystore and build scripts.
  • Use EAS when you want it, without requiring an EAS cloud build for the local pipeline.
  • Run the same workflow from a terminal, a local browser UI, or scripts committed to your project.

Quick start

From the root of an Expo project:

npx local-expo-build init

The setup wizard checks your environment, helps configure the Android package and release keystore, and adds two npm scripts to your project. Then build the artifact you need:

# Google Play upload
npm run build:android:aab

# Direct device installation or testing
npm run build:android:apk

The finished artifact is written under android/app/build/outputs/ and the CLI prints its absolute path and size when the build completes.

One-off build without scaffolding

Use runner mode when you do not want init to add files or scripts to your project:

npx local-expo-build doctor
npx local-expo-build build android --aab

Use --apk instead of --aab for an APK.

Install globally

npx is enough for most projects. To keep the command available globally:

npm install --global local-expo-build
local-expo-build init

What the build does

For a release Android build, the CLI normally:

  1. Checks the local toolchain and Expo configuration.
  2. Runs Expo prebuild and applies the Gradle version required by the detected Expo SDK.
  3. Bumps the app version and, when available, gets the next Android versionCode from EAS.
  4. Restores or configures the release keystore and injects the Gradle signing configuration.
  5. Runs assembleRelease for an APK or bundleRelease for an AAB.
  6. Optionally syncs the new versionCode back to EAS.
  7. Prints the final artifact path and size.

The pipeline is designed to recover the keystore after expo prebuild --clean, which can otherwise remove files under android/.

Choose a workflow

Scaffold mode — recommended for repeated builds

npx local-expo-build init
npm run build:android:aab

init adds an editable scripts/ build pipeline and these entries to package.json:

{
  "scripts": {
    "build:android:apk": "node scripts/build.js apk",
    "build:android:aab": "node scripts/build.js aab"
  }
}

The generated scripts are yours to review and customize. Refresh them later with:

npx local-expo-build update-scripts

Runner mode — no project files added

npx local-expo-build build android --aab

Runner mode is useful for one-off builds or when you prefer not to commit the generated pipeline.

Browser UI

npx local-expo-build ui

The UI runs on 127.0.0.1 and provides:

  • Environment Doctor checks and guided fixes.
  • Android APK/AAB builds with live logs.
  • Keystore import, generation, EAS fetch, and rehydration.
  • EAS project linking and eas.json setup when needed.
  • A scaffold action equivalent to init.

Useful options:

npx local-expo-build ui --port 3847 --no-open --logs

--logs mirrors safe server and build output to the terminal. Credential-like values and large base64 values are redacted.

UI screenshots

The UI guides you from setup through a completed release build:

Setup wizard and scaffold flow

Doctor showing environment issues and guided fixes

Doctor showing a ready-to-build environment

Keystore management and EAS credential actions

Android build in progress with live logs

Completed build with the generated artifact path

Requirements

All platforms

  • Node.js 20 or newer.
  • An Expo project with dependencies installed: npm install, pnpm install, or yarn.

Android builds

  • JDK 17 is recommended for Expo SDK 55.
  • Android SDK with ANDROID_HOME configured.
  • keytool on PATH, included with the JDK.
  • eas-cli is optional. It is only needed for EAS credential fetch, EAS project setup, or version-code synchronization.

Run this before your first build if you are unsure what is missing:

npx local-expo-build doctor

iOS builds

  • macOS only.
  • Xcode 14 or newer with Command Line Tools.
  • An Apple Developer account for distribution signing.
  • A distribution certificate (.p12) and provisioning profile.

Android signing

The first release build checks for a release keystore. If one is missing, the interactive setup can:

  • Rehydrate an existing EAS credentials.json and .jks.
  • Register an existing .jks file.
  • Generate a new keystore with keytool.
  • Fetch the project keystore through EAS.

Start the picker directly with:

npx local-expo-build keystore setup

Individual operations are also available:

npx local-expo-build keystore import       # use an existing .jks
npx local-expo-build keystore create       # generate a new keystore
npx local-expo-build keystore fetch        # download through EAS
npx local-expo-build keystore rehydrate    # restore from credentials.json

If credentials.json already references a downloaded keystore, rehydrate recreates keystore.properties and copies the keystore into android/app/ without asking for the passwords again.

Keep signing files private

keystore.properties and credentials.json contain plaintext keystore passwords. The setup flow adds them, along with keystore files, to .gitignore. Never commit or share them. Back up the keystore and its passwords securely: losing the original signing key can prevent updates to an app already published on Google Play.

Command reference

Setup and diagnostics

local-expo-build                          Run init inside an Expo project
local-expo-build init [options]           Scaffold scripts and run setup
local-expo-build doctor                   Check and optionally fix the environment
local-expo-build ui [options]             Launch the local browser UI
local-expo-build update-scripts [options] Refresh scaffolded scripts

init options:

--force        Overwrite existing scaffolded scripts
--no-doctor    Skip pre-flight checks
--no-keystore  Skip interactive keystore setup
--no-build     Skip the post-setup build prompt

Android

local-expo-build build android --aab
local-expo-build build android --apk

Common options:

--aab                  Build a release AAB (default)
--apk                  Build a release APK
--profile <name>       EAS profile used for version-code lookup (default: production)
--clean                Run expo prebuild --clean
--no-clean             Skip the clean prebuild prompt
--no-bump              Skip version bumping
--no-sync              Do not sync versionCode back to EAS
--no-prebuild          Reuse the existing native project
--debug                Build a debug APK without release signing or EAS
--max-ram <ram>        Set Gradle/Node memory, for example 4g or 8g

For CI or other non-interactive environments, use explicit flags and skip setup prompts when appropriate:

npx local-expo-build init --no-doctor --no-keystore --no-build
npx local-expo-build --dry-run build android --aab

--dry-run shows the planned pipeline without running the build or writing project files.

Dry-run output showing the planned build pipeline

iOS (experimental)

local-expo-build build ios --method app-store \
  --team-id ABCDE12345 \
  --bundle-id com.example.app \
  --profile-name "Your Distribution Profile"

Supported methods are app-store, ad-hoc, development, and enterprise. The scheme is detected automatically for the standard Expo prebuild output; use --scheme when needed.

The iOS pipeline runs Expo prebuild, xcodebuild archive, and xcodebuild -exportArchive, producing an IPA under ios/build/export/. You must install the .p12 in Keychain Access and the provisioning profile in Xcode/macOS yourself. Uploading to TestFlight or the App Store is not included.

Global options

These options can be used with the commands above:

--cwd <path>       Run against a different Expo project directory
--verbose          Print additional diagnostic output
--dry-run          Preview actions without making changes
--no-update-check  Skip npm and scaffold update checks
--yes-update       Apply an available CLI update without prompting

Run npx local-expo-build --help or append --help to any command for the complete current help text.

EAS: optional, not required

Local builds do not require an EAS account, eas.json, or an EAS cloud build. EAS is useful when you want to:

  • Store and fetch a team keystore.
  • Link the project and generate eas.json.
  • Allocate the next versionCode and sync it back after a build.
  • Submit a locally produced artifact using the rest of your EAS workflow.

For a project that already has a keystore on EAS:

npx local-expo-build keystore fetch
npx local-expo-build keystore rehydrate
npx local-expo-build build android --aab

If EAS is unavailable, the local keystore providers still work. Version-code synchronization is skipped with a warning when it cannot run; use --no-sync when managing versions yourself.

Files created or updated

Depending on the workflow, the CLI may create or update:

app.json                         expo.android.package and EAS project link
eas.json                         EAS build profile configuration, when configured
keystore.properties              Local Gradle signing configuration (private)
credentials.json                 EAS-compatible local credentials (private)
android/app/*.jks or *.p12       Release signing key (private)
scripts/                         Scaffolded, editable build pipeline
android/app/build/outputs/       Generated APK/AAB artifacts

The CLI adds sensitive signing files to .gitignore during setup. Review the changes before committing, especially if your project uses a custom app.config.* instead of app.json; dynamic config is read for checks but is not rewritten automatically.

Troubleshooting

The Android package is missing

Add an Android application ID to app.json, or run doctor and accept its fix:

{
  "expo": {
    "android": {
      "package": "com.example.myapp"
    }
  }
}

The keystore file is missing after prebuild

Rehydrate or re-import the signing key, then update the scaffolded scripts if this is an older project:

npx local-expo-build keystore rehydrate
npx local-expo-build init --force

eas credentials fails

EAS credential commands need a linked project and usually eas.json. Run:

eas init
eas build:configure --platform android
npx local-expo-build keystore fetch

Or use keystore create or keystore import to stay entirely local.

Google Play rejects the artifact

The most common causes are a reused versionCode or a different signing key. Avoid --no-sync unless you manage versioning yourself, and use the original release keystore for updates to an existing app.

Development

npm install
npm test
npm run build

To test a local package in another Expo project:

npm run build
npm pack
npm install ../local-expo-build/local-expo-build-<version>.tgz

Contributions are welcome. See CONTRIBUTING.md, CHANGELOG.md, and LICENSE.


Not affiliated with Expo or Google. “Expo” and “EAS” are trademarks of 650 Industries, Inc. This project is independently maintained and uses EAS public APIs where selected features require them.