v0.1.0 · early release

One file.
Two stores.
Ship.

appship releases your iOS and Android app to the App Store and Google Play from a single release/ folder. It runs on fastlane, so you never maintain a Fastfile again.

$ npm i -g appship-ai
~/Projects/word-bank
$ appship doctor
▸ Environment
  ✓ Node 22.12.0
  ✓ fastlane 2.232.2
▸ Security
  ✓ No key files tracked by git
  ✓ .gitignore protects release/keys/
▸ iOS · store listing
  ✓ Metadata OK for en-US, vi
▸ Android · questionnaire
  ✓ All answers present

  ✓ Ready — 0 warning(s)
$ appship upload --build
  ios: build/ios/ipa/WordBank.ipa
▸ fastlane ios upload
  android: build/app/outputs/bundle/release/app-release.aab
▸ fastlane android upload

Workflow

Five commands, from an empty repo to App Review.

Set up once per project, check everything, then repeat the last two every release.

  1. Once per project appship init

    Detects your framework, bundle id and package name, then writes release/ with commented templates and updates .gitignore.

  2. Before every upload appship doctor

    Checks tools, keys, character limits, image sizes and placeholder text, and fails on a key committed to git.

  3. First time only appship first-release

    Creates the iOS app, pushes the listing and App Privacy, and writes CHECKLIST.md for the steps the stores keep manual.

  4. Every release appship upload --build

    Runs your build command, then pushes the .ipa to TestFlight and the .aab to a Play track, with staged rollout.

  5. Every release appship submit

    Sends the iOS build to App Review and promotes the Android release to production, after you confirm.

What's automated

Honest about what the stores let a tool do.

Apple and Google keep some steps manual on purpose. appship automates what their APIs allow. For everything else, it gives you a checklist with your answers already filled in.

  • Automated appship does it
  • needs a login with 2FA, so not on CI
  • Checklist no API; copy your answers into the console
StepApp StoreGoogle Play
Create the app first-release --create-app ChecklistGoogle Play has no API for this
Upload a build AutomatedTestFlight Automatedinternal · alpha · beta · production, staged rollout
Listing text & screenshots Automatedpush and pull Automatedpush and pull
Store questionnaires AutomatedAge rating, export compliance, content rights, review contact ChecklistContent rating, data safety, target audience, ads, app access
App Privacy Uploaded from questionnaire.yml n/a
Submit AutomatedApp Review AutomatedPromote a track to production
Status AutomatedLive, in review, pending, latest TestFlight build AutomatedVersion codes per track

On Google Play, upload the very first bundle by hand. New personal developer accounts also need a closed test with 12 testers for 14 days before production.

Features

Everything around the binary, handled.

One config per project

Your app repo only gets a release/ folder. The release logic lives in the tool, so updating appship updates every project that uses it.

release/release.yml
app:
  name: "Word Bank"
  primary_locale: en-US
ios:
  bundle_id: com.ketch.wordbank
  artifact: "build/ios/ipa/*.ipa"
  build_command: "flutter build ipa --release"
android:
  package_name: com.ketch.wordbank
  track: internal
  rollout: 1         # 0.2 = 20% staged rollout
credentials:
  profile: ketch-studio

Store questions, answered once

Age rating, export compliance, content rights, reviewer contact. Write the answers in questionnaire.yml; appship fills in what the APIs allow and puts the rest into CHECKLIST.md.

release/questionnaire.yml
ios:
  export_compliance:
    uses_non_exempt_encryption: false
  content_rights:
    uses_third_party_content: false
  age_rating:
    gamblingSimulated: NONE
    violenceCartoonOrFantasy: NONE
    messagingAndChat: false
    ageAssurance: false

doctor catches it before the stores do

Character limits, invalid URLs, leftover TODOs, wrong image sizes, stale artifacts, missing keys. Every problem comes with the fix.

appship doctor
▸ iOS · store listing
  ✗ ios/metadata/en-US/subtitle.txt is 34 characters (max 30)
  ! ios/screenshots/vi has no 6.9"/6.5" iPhone screenshot
▸ Android · store listing
  ✗ images/icon.png is 1024x1024, expected 512x512

  ✗ 2 error(s), 1 warning(s)

Keys stay out of git

Keys resolve from environment variables, then release/keys/ (gitignored), then a profile in ~/.appship stored with mode 600. Passwords are masked in --dry-run.

Works with any stack

appship runs your build command and picks up the .ipa and .aab. Flutter, React Native, Cocos Creator and native projects are detected on init.

Asks before it writes

Submitting, pushing to production and overwriting a live listing all ask for confirmation. In CI, pass --yes explicitly.

Ready for CI

Pass the .p8 key as plain text or base64 in APPSHIP_ASC_KEY. A GitHub Actions workflow is included in examples/.

Ready to ship?

appship is distributed on npm. You need Node.js 22+, fastlane, and macOS for iOS builds (Android also works on Linux).

$ npm i -g appship-ai
Integration guide →

v0.1.0 is covered by tests and dry-runs but has not been run against the live stores yet. Start with --dry-run and read-only commands such as appship status.