Tiny CLI to bump iOS build numbers, archive/export, and upload to TestFlight.
npm install react-native-paperplane

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
- 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
``bash`
npm install -D react-native-paperplaneor
bun add -d react-native-paperplane
`bash`
npx react-native-paperplane --dry-run
npx react-native-paperplane
Bun alternative:
`bash`
bunx react-native-paperplane --dry-run
bunx react-native-paperplane
`bash`run locally without publishing
bun src/cli.js --helpor
node src/cli.js --help
Optional global-style bin for development:
`bash`
npm link
paperplane --help
`bash`
paperplane [options]
- --build-number : Set explicit build number (default: current + 1)--message
- : 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_SCHEME
- IOS_WORKSPACE
-
- ios/ contains an Xcode workspace (or set IOS_WORKSPACE).
- Info.plist is at ios/
- Build number is read from text in app.config.ts, app.config.js, or app.json.
Artifacts are written to:
``
ios/build/testflight/
`bashdry run
paperplane --dry-run
FAQ
Why 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.
Publishing checklist
- Confirm the package name is available on npm:
npm view react-native-paperplane.
- Update package.json version.
- Run a quick help check: node src/cli.js --help.
- Dry pack: npm pack and sanity-check the tarball contents.
- Publish: npm publish --access public.Notes:
-
--access public is only required for scoped packages, but harmless for unscoped.`text
:
= ..=
+
=..= @%@..%@@
+%%@.....+%@...@
@@@..:...-:.+%@@.-..@
- @%@.-........-..#++@....--@@
%@%@...:.....-......#++%@..:...:.@ .
#%%@....+.-....=.:.+.. .#+*@%..-....:..@ =
@@@.....-................=.#++=%@..=...-:::=.@
@%%=...::.............:......++==%@........:=::-.@ - +
= @@..::.-.:::...... ...-.......-.@++@%........::=::--.@ .
. @@.::::.:.......+.......@+%++@#.........=#::::=..@
+ + @%......:. ...-..+++%%..........:=:::.+:-.@@
+ . @+.......#++++@%.....-...=.----.-=---..@ =
+ . @+@%.**+++%@......#..=.--:.-+-:=--+.@@
@=+@.*%......:....*:---:::%:.--.=@
@-@:+*@.%@ ......::::.=:::--:-..@@
+ ---=+@==#%#%..:.:.::-.:*::-..@@
@:-+.===%#*@..:....::::+..@@
@%=@+==-+==@@ @%.....*...@@
@@+.:-=-@@ @%..=...@%
@@.-@@ @@..@@
#:@ * @% 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
``