@johnhaup/expo-local-ship
v2.0.0
Published
CLI to build and submit Expo apps locally
Readme
expo-local-ship
CLI to build and submit Expo apps locally.
- iOS submits via
xcrun altoolusing an App Store Connect API key — fast, reliable, fully automated. - Android submits via
eas submit.
Requirements
easCLI installed (npm install -g eas-cli)- A
production-localbuild profile ineas.jsonwithcredentialsSource: "local" - A
credentials.jsonwith local signing credentials (docs)
Optional: a ship:prebuild script in package.json for any steps that need to run before the build.
Setup
npm install -D @johnhaup/expo-local-shipAdd scripts to package.json:
{
"scripts": {
"ship:ios": "expo-local-ship ios",
"ship:android": "expo-local-ship android"
}
}Minimum eas.json
{
"build": {
"production-local": {
"credentialsSource": "local",
"distribution": "store",
"developmentClient": false,
"autoIncrement": true
}
},
"submit": {
"production": {
"android": {
"serviceAccountKeyPath": "./path-to-service-account.json",
"track": "internal"
}
}
}
}The
submit.productionconfig is only needed for Android. iOS submission uses altool directly.
iOS: App Store Connect API Key (one-time)
iOS submission uses xcrun altool with an App Store Connect API key. This is a one-time setup that works across all your apps.
Run the interactive setup:
npx expo-local-ship setupThis will:
- Prompt for your API Key ID and Issuer ID (from App Store Connect → Integrations → App Store Connect API)
- Prompt for the path to your
AuthKey_<KEY_ID>.p8file and copy it to~/.appstoreconnect/private_keys/ - Save your config to
~/.expo-local-ship.json
- Go to App Store Connect → Users & Access → Integrations → App Store Connect API
- Generate a new key with Admin or App Manager role
- Note your Issuer ID and Key ID
- Download the
AuthKey_<KEY_ID>.p8file (you can only download it once) - Place the
.p8file in~/.appstoreconnect/private_keys/
Then create ~/.expo-local-ship.json:
{
"apiKey": "YOUR_KEY_ID",
"apiIssuer": "YOUR_ISSUER_ID"
}Alternatively, use environment variables:
export ASC_API_KEY=YOUR_KEY_ID
export ASC_API_ISSUER=YOUR_ISSUER_IDEnvironment variables take precedence over the config file.
Usage
# Build + submit iOS (via altool)
bun ship:ios
# Build + submit Android (via eas submit)
bun ship:android
# Build both platforms
npx expo-local-ship both
# Build only, skip submission
npx expo-local-ship ios --no-submit
# Build + open in Transporter app instead of altool
npx expo-local-ship ios --transporterIf no platform argument is provided, you'll be prompted to choose.
How it works
- Validates
eas.jsonhas aproduction-localprofile andcredentials.jsonexists - Runs
ship:prebuildscript if present in yourpackage.json - Runs
eas build --profile production-local --local - Submits the artifact:
- iOS:
xcrun altool --upload-appwith your API key (or Transporter with--transporter) - Android:
eas submit --profile production
- iOS:
Build artifacts are saved to ./build/ in your project root.
