Expo tutorial

Publish an Expo app: prebuild, release build, and store checklist

This guide prepares an Expo project for App Store and Google Play submission through Shiptavio. It covers app configuration, native generation, public environment values, release builds, and the files to send.

By Shiptavio · Updated 26 October 2026 · 10 min read · Expo

1. Confirm the app is a fit

Shiptavio publishes free apps under the Apple Developer and Google Play organization accounts of our Malaysia-based organization. Check the commercial and category limits first.

  • The app is free. No paid download, in-app purchase, or digital subscription.
  • The app is not in a prohibited category.
  • Every API uses production HTTPS.
  • You own the code, name, logo, and content.
  • You can provide a demo account if the app has a login.

2. Complete app.json or app.config.ts

The Expo config is the source of truth for the native project. A missing bundle identifier or package name will stop the build.

  • Keep the version, iOS buildNumber, and Android versionCode current.
  • Add config plugins for permissions, native modules, deep links, icons, and splash screens.
  • If you use app.config.ts, make sure it does not depend on a secret that you cannot share.
  • Do not change the bundle identifier or package name after the first store publish.
Example app.json
{
  "expo": {
    "name": "My App",
    "slug": "my-app",
    "scheme": "myapp",
    "version": "1.2.0",
    "ios": {
      "bundleIdentifier": "com.yourcompany.myapp",
      "buildNumber": "42"
    },
    "android": {
      "package": "com.yourcompany.myapp",
      "versionCode": 42
    }
  }
}

3. Generate and check the native project

Expo can generate ios/ and android/ from the config. Shiptavio runs prebuild when the project relies on those generated folders, but a local prebuild catches plugin errors early.

  • If the project commits ios/ and android/, include them in the source.
  • If it relies on continuous native generation, include every config plugin and the prebuild command.
  • Check that app icons, splash screens, and permission strings survive prebuild.
  • Remove generated folders from the zip if they are not part of your source of truth.
Generate native projects
npx expo prebuild --clean
Check the Expo setup
npx expo-doctor

A clean prebuild is the closest local check to what Shiptavio will run. If it fails, send the full error in the build notes.

4. Handle environment values safely

Expo bakes EXPO_PUBLIC_* values into the app bundle. They are public. Private keys belong on your server, not in the app.

  • Use EXPO_PUBLIC_* for public values such as a production API URL.
  • Never put a private API key, signing secret, or service-role key in the app.
  • Add non-secret production values in the Shiptavio submission form or with --env-file in the CLI.
  • If you use EAS secrets, remember that Shiptavio's build does not read your EAS project. Provide the values through the submission form or a runtime config service.

5. Run a native release build

EAS Build is not required for Shiptavio. We build the native project on our Mac. You can still use EAS for your own development builds.

  • Use npm ci, yarn install --frozen-lockfile, or pnpm install --frozen-lockfile to match the lockfile.
  • EAS Build profiles are optional. If your project depends on EAS-hosted secrets, provide those values through the submission form instead.
  • Remove development clients, debug menus, and test deep links from the release build.
Install and prebuild
npm ci
npx expo prebuild --clean
Local iOS and Android checks (iOS needs a Mac)
npx expo run:ios --configuration Release
npx expo run:android --variant release

The exact native commands depend on your project. If your build needs a custom script, put it in the build command field.

6. Package the source

Send the Expo source, not a finished binary. Include the config, lockfile, and native folders when they are part of the project.

  • Include app.json or app.config.ts, package.json, the lockfile, and source files.
  • Include ios/ and android/ if the project commits them.
  • Leave out node_modules, .expo, dist/, build output, .env files, keystores, and private keys.
  • The source limit is 200 MB.
Create a source archive
git add . ':!**/node_modules'
git commit -m "Prepare Expo release"
git archive --format=zip -o my-app-source.zip HEAD

7. Submit to Shiptavio

Create the app record, choose Expo, and add the source and listing details.

  • Add the exact prebuild and build command.
  • Add non-secret production environment values.
  • Include icons, screenshots, store text, privacy policy, and a demo account if needed.
  • Tell us in the build notes if the app uses EAS Update or another OTA service.

8. Updates, OTA, and common failures

A store update uses one release credit. EAS Update is a separate OTA channel and is not managed by Shiptavio.

  • runtimeVersion mismatch: align the store build and the OTA update before you publish either.
  • Missing bundle identifier or package: add ios.bundleIdentifier and android.package.
  • Config plugin failure: run npx expo prebuild --clean locally and send the error.
  • Version code not incremented: both stores reject a duplicate build number.
  • New Architecture or Hermes mismatch: document the setting in the build notes.
  • Do not send EAS credentials or private signing keys.

Common questions

Can I publish an Expo app without EAS?
Yes. Shiptavio runs prebuild and the native release build on its Mac. EAS is optional for your own development and OTA workflow.
Does Shiptavio support EAS Update?
No, not directly. EAS Update is your OTA channel. Shiptavio publishes the store build. Tell us before submission so the runtime version and store build are aligned.
Do I need to commit ios/ and android/?
It depends on your workflow. If you use continuous native generation, send the config plugins and the prebuild command. If you commit the folders, include them in the source.
Are EXPO_PUBLIC_ variables secret?
No. They are embedded in the app bundle. Use them for public URLs and configuration, never for private API keys.
Can I send a build from EAS?
No. Shiptavio signs with its own certificates, so it has to build from source. A binary built by EAS uses your credentials and cannot be reused for our submission.
What happens if prebuild fails?
We send the error back before the build starts. Fix the config plugin or the source and resubmit. A source failure does not use a release credit.

Related guides

Ready to send the project?

Register the app and add the source. A person reviews the project before the build starts.