Tiny CLI to bump iOS build numbers, build/export with Xcode, and upload to TestFlight.
License: MIT
- One-command TestFlight release flow for iOS
- Supports app.config.ts, app.config.js, and app.json (text-only parsing)
- Dry run mode and clean git enforcement
- Deterministic output paths for build artifacts
- Release prerequisites checked before build-number changes or commits
- Upload passwords redacted from command failures and child-process output
- Node 18+ or Bun
- Xcode Command Line Tools
- Transporter app installed and signed in (for iTMSTransporter)
- Repo with ios/ and an Xcode workspace
- One of: app.config.ts, app.config.js, app.json
npm install -D react-native-paperplane
# or
bun add -d react-native-paperplanenpx react-native-paperplane --dry-run
npx react-native-paperplaneBun alternative:
bunx react-native-paperplane --dry-run
bunx react-native-paperplane# run locally without publishing
bun src/cli.js --help
# or
node src/cli.js --helpOptional global-style bin for development:
npm link
paperplane --helpRun the offline regression tests with npm test (Node 18+). The tests use fake
Git/Xcode/Transporter commands and dummy credentials; they do not build an app or
contact App Store Connect.
Paperplane uses the selected Xcode's iphoneos SDK and the supported
app-store-connect export method; it does not pin an iOS SDK version. Export
options omit obsolete Bitcode keys. The app itself must satisfy the selected
SDK's requirements, including UIKit scene support when building with iOS 27.
For Expo apps, regenerate the native project and reconcile Pods after updating
native dependencies; Paperplane does not run Expo prebuild or CocoaPods for you.
Before changing either build number or making the release commit, a real run
checks Xcode, the iPhoneOS SDK, and Git author/committer identities. Upload runs
also check credentials and the local Transporter executable. --skip-upload
does not require upload credentials or Transporter. --dry-run remains a
non-mutating preview without build/upload prerequisite checks.
Preflight cannot guarantee signing, export, or Apple's acceptance of an upload. Failures after the build-number commit still leave that commit in place; inspect the current build number before retrying. Password redaction protects Paperplane's console output, not operating-system process argument visibility or logs written directly by external tools.
paperplane [options]--build-number <n>: Set explicit build number (default: current + 1)--message <msg>: Override git commit message--dry-run: Show actions without modifying files or running build/upload--allow-dirty: Skip clean git check--skip-upload: Build/export only; skip upload-h, --help: Show help
Required for upload (Apple ID auth only):
ASC_APPLE_IDASC_APP_PASSWORD
Optional:
ASC_ITC_PROVIDER
iOS overrides:
IOS_APP_NAMEIOS_SCHEMEIOS_WORKSPACE
- ios/ contains an Xcode workspace (or set IOS_WORKSPACE).
- Info.plist is at ios//Info.plist.
- Build number is read from text in app.config.ts, app.config.js, or app.json.
Artifacts are written to:
ios/build/testflight/<runId>/
# dry run
paperplane --dry-run
# explicit build number
paperplane --build-number 42
# build only, no upload
paperplane --skip-uploadWhy Bun? Bun is fast and works great for CLI workflows. This package also runs on Node 18+.
Transporter errors? Install Transporter from the Mac App Store and sign in once.
- Confirm the package name is available on npm:
npm view react-native-paperplane. - Update
package.jsonversion. - Run a quick help check:
node src/cli.js --help. - Dry pack:
npm packand sanity-check the tarball contents. - Publish:
npm publish --access public.
Notes:
--access publicis only required for scoped packages, but harmless for unscoped.
:
= ..=
+
=..= @%@..%@@
+%%@.....+%@...@
@@@..:...-:.+%@@.-..@
- @%@.-........-..#++@....--@@
%@%@...:.....-......#++%@..:...:.@ .
#%%@....+.-....=.:.+.. .#+*@%..-....:..@ =
@@@.....-................=.#++=%@..=...-:::=.@
@%%=...::...*......*....:......++==%@........:=::-.@ - +
= @@..::.-.:::...... ...-.......-.@*++@%........::=::--.*@ .
. @@.::::.:.......+.......@+%++@#.........=#::::=..@
+ + @%.....*.:. ...-..++*+%%..........:=:::.+:-.@@
+ . @+.......#++++@%.....-...=.----.-=---..@ =
+ . @+@%.**+++%@......#..=.--:.-+-:=--+.@@
@=+@.***%......:....*:---:::%:.--.=@
@-@:+*@.%@ ......::::.=:::--:-..@@
+ ---=+@==#%#%..:.:.::-.:*::-..@@
@:-+*.===*%#*@..:....::::+..@@
@%=@+==-+==@@ @%.....*...@@
@@+.:-=-@@ @%..=...@%
@@.-@@ @@..@@
#:@ * @%
PPPPPP AAA PPPPPP EEEEEEE RRRRRR PPPPPP L AAA N N EEEEEEE
P P A A P P E R R P P L A A NN N E
P P A A P P E R R P P L A A N N N E
PPPPPP A A PPPPPP EEEEEE RRRRRR PPPPPP L A A N N N EEEEEE
P AAAAAAA P E R R P L AAAAAAA N NN E
P A A P E R R P L A A N N E
P A A P EEEEEEE R R P LLLLLLL A A N N EEEEEEE