Xyvenra Mobile build and release workflows
The builder's Home screen subtitle appears beneath the app name in the phone preview, Snack preview, and generated project. It is included in browser drafts, account saves, and builder backups. Existing saved drafts receive the previous default subtitle when loaded.
Xyvenra Mobile generates an Expo React Native project and ready-to-use EAS profiles. Expo runs the builds, submissions, and updates under the developer's Expo account. Xyvenra does not run build workers or charge for these actions.
Dispatch a workflow you already have on Expo
The signed-in Mobile page and POST /api/platform/v1/eas can ask Expo to run a workflow that already exists in your Expo project. You supply your Expo access token, the Expo project UUID, the 40-character git commit, and the workflow file name, such as preview.yml. Xyvenra forwards that token to https://api.expo.dev/v2/workflows/dispatch for that request and does not store it. Xyvenra does not upload the in-app starter and does not pay Expo. If the workflow starts an EAS build, Expo bills your Expo account. Creating or downloading a starter does not dispatch anything. A missing token, commit, or workflow file does not start a build.
Run a starter online with Expo Snack
From the Mobile builder, choose Run starter in Expo Snack. The link opens Expo's editor in a new tab and starts the React Native starter in the Web preview. Add, toggle, or remove a sample task or habit, or edit a sample note. Expo also offers a My Device option for compatible Expo Go installations.
In a downloaded task, habit, or notes starter, use the pencil beside an item to load its title into the entry field. Save with the check button or cancel with ×. Notes also let you edit the note body directly. Item changes save locally on the device or browser.
Generated projects include Items, Overview, and Backup screens. Overview summarizes item counts, task or habit completion, or the character count of note text, and shows recent items. Backup holds the local export and restore controls and explains the storage boundary. Switching screens does not copy data to Xyvenra or Expo.
Use the up and down arrows beside an item to reorder the list. The first item's up control and the last item's down control are disabled. Reordering keeps each item's completion state or note body and saves with the app's local data.
Search the generated app's list by item title; the notes starter also searches note bodies. Search is case-insensitive and does not change the stored list. Use Clear search to show all items again. A no-results message appears when nothing matches.
Task and habit starters also provide All, Active, and Completed filters. They combine with search and only affect the displayed rows; toggling items, reordering, and local persistence continue to use the full list. The notes starter has no completion filter.
The link sends the generated App.js, including the selected starter, app name, subtitle, accent color, and a built-in example. Your tasks, habits, note text, bundle identifier, and Xyvenra account saves stay in Xyvenra. Snack selects its supported SDK independently of the ZIP download. Snack edits are separate from your Xyvenra draft. Use the Xyvenra ZIP for the full project, your seed data, and the EAS profiles.
Run current draft in Expo Snack is an optional second action. It asks before sending your current item titles, note bodies, completion states, app name, and accent through the Snack URL. Anyone with that link can read the included data. The Snack preview assigns new item IDs and replaces control characters, including line breaks and tabs in note text, with spaces. It does not preserve those details like the downloadable project ZIP and supported backups do. Snack chooses its own SDK and does not include the full EAS project. Very large drafts cannot fit in a practical Snack URL; download the ZIP to test those. Changes made in Snack do not return to your Xyvenra draft.
Back up installed-app data
Generated task, habit, and notes apps can export or restore their local item data with Export backup and Import backup. Native apps offer the JSON through the device's share sheet. Web builds try the browser clipboard and leave the JSON available for manual copy if clipboard access is unavailable.
Backups use a versioned Xyvenra Mobile JSON format and contain only the current starter app's items. They are limited to 100 items and 250 KB; titles are limited to 160 characters and note text to 1,000 characters. Import accepts only the matching starter type, validates the fields and limits, previews how many items will replace the current list, and requires an explicit Restore on this device action.
The Items screen reports whether the latest local save succeeded. If storage is unavailable, export a backup before leaving. This is a manual local backup, not account sync. Xyvenra does not receive the exported JSON. It excludes builder settings, account saves, provider credentials, and data from other apps. The app still stores its active list in unencrypted AsyncStorage, scoped to that installation or browser origin; clearing app/browser data can erase it. Store backups somewhere private. Mobile/EAS workflow support and provider limits are described below.
App icon and launch screen
The downloaded ZIP generates a 1024-pixel PNG app icon and a transparent launch-screen mark from the selected accent. The native config uses Expo's splash-screen plugin. The icon and launch screen are generated in your browser and included in the ZIP; Xyvenra does not upload them. Expo Go shows its own launch screen, so install a fresh preview or production build to check the configured launch screen. Rebuild after changing native image assets or app config. See Expo's app icon and splash screen guide (opens in a new tab).
Export a standalone web app
Download and unzip the Expo project. With Node.js 24.3 or later in the 24.x release line, run npm install and npm run export:web. Metro writes a single-page web build to dist/. Run npm run serve:web to try the production output locally. You can deploy the contents of dist/ to the root of a static site without an Expo account. Expo Hosting is another option after signing in and linking the project. Run npx eas-cli@latest deploy to create a preview deployment. See the Expo web publishing guide (opens in a new tab).
The export contains the builder's initial item text in its JavaScript bundle. Remove any private seed data before publishing. Visitor edits use browser storage for that origin and stay separate from the Xyvenra builder and native app installations.
Profiles in eas.json
- development creates an internal development-client build for iterating with
expo start --dev-client. - preview creates an internal Android APK or iOS installable build for tester distribution.
- ios-simulator creates a standalone build that runs in the iOS Simulator; it does not create a device-installable IPA.
- production creates a store-ready build with remote app-version incrementing.
- submit:production selects the production submission profile.
- submit:testflight is the GitHub Actions /
eas.jsonprofile this project uses to submit a finished iOS production build to TestFlight only. It is not an App Store release.
The development profile needs the version of expo-dev-client compatible with the selected Expo SDK. Run the generated npm run setup:development script before the first development-client build. Run npm run check:dependencies to check that installed packages match the selected SDK; this check does not modify the project. If the check reports mismatches, review them and run npx expo install --fix only if you want Expo to update the project's dependencies. See Expo's CLI dependency validation guide (opens in a new tab) and EAS Build configuration guide (opens in a new tab).
Link the project and build
The ZIP already includes a complete eas.json with development, preview, iOS Simulator, and production profiles. Do not run eas build:configure over this file: that command creates default profiles for projects that do not already have eas.json.
- Install Node.js, unzip the project, and run
npm install. - Create or sign in to the Expo account that should own the app. In the project folder run
npx eas-cli@latest login, thennpx eas-cli@latest init. Choose the account and create or link the project. Expo adds its generated project UUID toextra.eas.projectIdinapp.json. - Before your first native build, review
expo.ios.bundleIdentifierandexpo.android.packageinapp.json. The generated suggestion iscom.xyvenra.<appname>; replace it with an identifier you control and that is unique in the relevant app store. Keep the same IDs for updates to that published app. - Run the desired command. The first EAS build guides you through creating or selecting signing credentials and securely stores managed credentials with Expo.
| Goal | Command |
|---|---|
| Android internal APK | npm run build:preview -- --platform android |
| iOS device preview | npm run build:preview -- --platform ios |
| iOS Simulator build | npm run build:ios-simulator |
| Android production app bundle and iOS production build | npm run build:production -- --platform all |
| Submit completed production builds | npm run submit:production -- --platform all |
For development builds, install the SDK-compatible client first with npm run setup:development, then run npm run build:development -- --platform android or npm run build:development -- --platform ios. After installing the development build on a device or emulator, run npm run start:development to open the project in that client. Preview builds are internal installable builds, while production builds use store distribution settings. The generated ZIP README lists these commands alongside the exact account-linking steps.
Production builds and submissions require the matching Apple Developer / App Store Connect and Google Play developer accounts, app listings, and signing or submission credentials. EAS can guide you through its credential setup. Never put passwords, private keys, or Expo access tokens in the generated project or commit them. An interactive CLI login does not require creating or pasting an API token. For CI automation only, store an EXPO_TOKEN in the CI provider's encrypted secret settings; this ZIP does not contain a token or any credentials.
Build in your own GitHub account
The project ZIP also includes four GitHub Actions workflows that need no Expo account, plus thirteen more that use your Expo token: one starts an EAS cloud build, one submits a finished store-signed iPhone IPA to TestFlight in your App Store Connect account, one publishes an over-the-air JavaScript and asset update with EAS Update, one rolls back a bad EAS Update, one pauses or resumes an EAS Update channel, one starts, edits, or reverts a per-update EAS Update rollout, one checks that the project is ready to build or submit later, without starting a paid build, submit, or publish, one lists, views, downloads a finished simulator or emulator artifact, or cancels an EAS cloud build in your Expo account, without starting a new build, one generates or compares EAS fingerprints in your Expo account, without starting a paid EAS build, one lists, views, or inspects insights for published EAS Updates in your Expo account, without publishing, rolling back, editing, or deleting an update, one lists, views, or cancels EAS submissions in your Expo account, without starting or retrying a submit, one lists, views, or inspects insights for EAS Update channels in your Expo account, without creating, editing, pausing, resuming, protecting, rolling out, or deleting a channel, and one lists or views EAS Update branches in your Expo account, without creating, deleting, or renaming a branch. Push the unzipped project to a GitHub repository you own, open Actions, choose a workflow, and select Run workflow. None of them runs on push, pull request, or a schedule.
| Workflow | Runner | Result |
|---|---|---|
.github/workflows/xyvenra-android-apk.yml | ubuntu-24.04 | A test-signed Android APK artifact for installing on your own devices. Expo's generated release build uses the debug signing key, so Google Play will not accept it. |
.github/workflows/xyvenra-android-aab.yml | ubuntu-24.04 | A release Android App Bundle (.aab) signed with your own upload key from your repository's Actions secrets. This is the file you upload to Google Play. |
.github/workflows/xyvenra-android-play-upload.yml | ubuntu-24.04 | Builds that same signed .aab, then uploads it as a draft on the internal testing track in your own Google Play Console. Testers do not receive it until you complete the release in Play Console. |
.github/workflows/xyvenra-ios-simulator.yml | macos-15 | An unsigned iOS Simulator .app in a .tar.gz artifact. It runs in the Simulator on a Mac with Xcode and cannot be installed on an iPhone. |
.github/workflows/xyvenra-eas-build.yml | ubuntu-24.04 | Starts an EAS cloud build with your EXPO_TOKEN secret. On platform ios and profile production, Expo compiles a store-signed iPhone IPA on Expo's servers. The binary stays on Expo; this job does not attach it as a GitHub artifact. |
.github/workflows/xyvenra-eas-submit-testflight.yml | ubuntu-24.04 | Submits a finished store-signed iOS production IPA to TestFlight in your own App Store Connect account using official eas submit --non-interactive. It does not submit the app for App Store review. |
.github/workflows/xyvenra-eas-update.yml | ubuntu-24.04 | Publishes a JavaScript and asset update to a channel in your own Expo account using official eas update --non-interactive. An OTA update cannot add native code or native dependencies. It does not submit to the App Store or Google Play. |
.github/workflows/xyvenra-eas-update-rollback.yml | ubuntu-24.04 | Republishes a previous update by group ID, or rolls clients back to the update embedded in the build, using official eas update:republish --group --non-interactive or eas update:roll-back-to-embedded --non-interactive. It does not publish a new JavaScript bundle from the current commit, and it does not submit to the App Store or Google Play. |
.github/workflows/xyvenra-eas-channel-pause.yml | ubuntu-24.04 | Pauses or resumes an existing EAS Update channel using official eas channel:pause --non-interactive or eas channel:resume --non-interactive after confirming the channel exists with eas channel:view --non-interactive. Pausing keeps clients on their current update and prevents new updates; resuming starts serving updates again. This is not a rollback, does not publish a new JavaScript bundle, and does not submit to the App Store or Google Play. |
.github/workflows/xyvenra-eas-update-rollout.yml | ubuntu-24.04 | Starts, edits, or reverts a per-update EAS Update rollout in your own Expo account using official eas update --rollout-percentage --non-interactive, eas update:edit --rollout-percentage --non-interactive, or eas update:revert-update-rollout --group --non-interactive. A rollout cannot add native code and does not submit to the App Store or Google Play. |
.github/workflows/xyvenra-eas-release-preflight.yml | ubuntu-24.04 | Checks that the project is ready to build or submit later, without starting a paid build, submit, or publish, using official eas whoami, eas project:info, eas config --platform --profile --non-interactive, and pinned npx --yes expo-doctor@1.21.8. |
.github/workflows/xyvenra-eas-build-status.yml | ubuntu-24.04 | Lists, views, downloads a finished simulator or emulator artifact, or cancels an EAS cloud build in your own Expo account, without starting a new build. Official eas build:download is for simulator or emulator builds only. |
.github/workflows/xyvenra-eas-fingerprint.yml | ubuntu-24.04 | Generates or compares EAS fingerprints in your own Expo account using official eas fingerprint:generate --non-interactive or official eas fingerprint:compare --non-interactive, without starting a paid EAS build. A matching fingerprint may mean you can reuse an existing native build and publish a JavaScript update instead; this job does not decide that for you. |
.github/workflows/xyvenra-eas-update-status.yml | ubuntu-24.04 | Lists, views, or inspects insights for published EAS Updates in your own Expo account using official eas update:list --non-interactive, official eas update:view (optional official --insights; official help does not list --non-interactive, so this job does not invent one), or official eas update:insights --non-interactive, without publishing, rolling back, editing, or deleting an update. |
.github/workflows/xyvenra-eas-submit-status.yml | ubuntu-24.04 | Lists, views, or cancels EAS submissions in your own Expo account using official eas submit:list --non-interactive, official eas submit:view (optional official --json; official help does not list --non-interactive, so this job does not invent one), or official eas submit:cancel --non-interactive, without starting or retrying a submit. |
.github/workflows/xyvenra-eas-channel-status.yml | ubuntu-24.04 | Lists, views, or inspects insights for EAS Update channels in your own Expo account using official eas channel:list --non-interactive, official eas channel:view [NAME] --non-interactive, or official eas channel:insights --channel --runtime-version --non-interactive, without creating, editing, pausing, resuming, protecting, rolling out, or deleting a channel. |
.github/workflows/xyvenra-eas-branch-status.yml | ubuntu-24.04 | Lists or views EAS Update branches in your own Expo account using official eas branch:list --non-interactive or official eas branch:view [NAME] --non-interactive, without creating, deleting, or renaming a branch. |
The APK, App Bundle, Play upload, and Simulator workflows install dependencies, run npx expo prebuild --clean for their platform, and build with Gradle or xcodebuild. They use no Expo token. The APK and Simulator workflows use no Apple Developer account, Google Play account, or repository secrets. Third-party actions in every workflow are pinned to full commit SHAs, the checkout does not keep GitHub credentials, and GitHub artifacts from the first four workflows expire after 7 days.
GitHub runs these jobs in your account and bills your repository's Actions usage. Standard runners are free on public repositories; private repositories draw from your plan's included Actions usage, and macOS minutes cost more than Linux minutes. See GitHub Actions billing (opens in a new tab). Xyvenra does not start these workflows, receive their artifacts, hold your signing keys, or pay for them.
Play-ready Android App Bundle
xyvenra-android-aab.yml runs ./gradlew bundleRelease after prebuild and signs the bundle with an upload key you create and keep. Xyvenra never receives the key, cannot recover it, and cannot sign for you. With Play App Signing (opens in a new tab), Google keeps the app signing key that users' devices trust; your upload key proves each bundle came from you, and Google Play support can reset a lost upload key.
Create an upload key on your own computer and back it up outside the repository:
keytool -genkeypair -v -storetype PKCS12 -keystore upload-keystore.jks -alias upload -keyalg RSA -keysize 2048 -validity 10000
base64 -w 0 upload-keystore.jks > upload-keystore.jks.base64
On macOS, encode it with base64 -i upload-keystore.jks -o upload-keystore.jks.base64. Then, in the GitHub repository, open Settings → Secrets and variables → Actions and add these repository secrets:
| Secret | Value |
|---|---|
ANDROID_KEYSTORE_BASE64 | The contents of upload-keystore.jks.base64 |
ANDROID_KEYSTORE_PASSWORD | The keystore password |
ANDROID_KEY_ALIAS | The key alias (upload in the example) |
ANDROID_KEY_PASSWORD | The key password (the same as the keystore password for a PKCS12 keystore) |
- Delete the
.base64file. The generated.gitignorealready ignores*.jksand*.keystore; never commit a keystore or password. - Run Android App Bundle for Google Play and enter a
version_codelarger than any bundle already uploaded for the app. The workflow writes it toexpo.android.versionCodeinapp.jsonon the runner only. - Download the
android-play-aabartifact and uploadapp-release.aabin Google Play Console (opens in a new tab) yourself, or use the optional Play upload workflow below.
The job fails before building if any of the four secrets is missing or the version code is not a whole number from 1 to 2,100,000,000. After building, it compares the bundle's signing certificate with your upload key and refuses to publish an artifact that does not match, so a debug-signed bundle never reaches the artifact list. The keystore is decoded into the runner's temporary directory and deleted before the artifact upload.
Publishing still needs your own Google Play developer account (a one-time US$25 registration), an app listing, content declarations, and Google's review. Personal developer accounts created after November 13, 2023 must run a closed test with at least 12 testers opted in for 14 consecutive days before they can apply for production access. See Google's testing requirements for new personal developer accounts (opens in a new tab). Xyvenra does not publish apps to Google Play or the App Store.
Upload a draft to Google Play internal testing
xyvenra-android-play-upload.yml is optional and runs only when you start it from the Actions tab. It builds and signs the App Bundle the same way as xyvenra-android-aab.yml, then uploads that signed bundle to your Google Play Console as a draft on the internal testing track. It does not roll out to production, and internal testers do not receive the build until you complete the release in Play Console. This default is the safer option: a completed production rollout is never the target. Xyvenra does not run, receive, or pay for the upload. GitHub bills the repository owner; the app stays on your Play developer account. You keep the upload key and the service-account JSON.
Before you run it:
- Complete the Play-ready App Bundle setup above, including the four keystore secrets.
- Have a Google Play developer account (a one-time US$25 registration) and an app listing whose package name matches
expo.android.packageinapp.json. - In Google Cloud, create a service account, enable the Google Play Android Developer API (opens in a new tab), and download its JSON key. In Play Console, invite that service account with permission to release to testing tracks. See Google's API access instructions (opens in a new tab).
- In the GitHub repository, add a repository secret named
PLAY_SERVICE_ACCOUNT_JSONcontaining the full JSON key. Never commit the file; the ZIP does not include one.
Then open Actions and run Upload a Play internal testing draft. Enter a version_code larger than any bundle already uploaded for the app. The job fails before building if a signing secret or the service-account JSON is missing or malformed, or if the package name in app.json is invalid. After building, it uses the same signing-certificate check as the App Bundle workflow and will not upload a bundle that does not match your upload key. The keystore and service-account JSON are deleted from the runner before the GitHub artifact is uploaded. You can still download the android-play-aab artifact.
The upload creates a draft on the internal testing track and does not send the Play Console edit for review (changesNotSentForReview). Complete and publish the draft yourself in Play Console when you are ready. A draft or internal upload does not by itself satisfy store production requirements, including the 12-tester / 14-day closed test for new personal accounts created after November 13, 2023.
EAS cloud build from your GitHub repository
In your GitHub repo, run the EAS workflow with your own Expo token; Expo bills your Expo account.
xyvenra-eas-build.yml is the bring-your-own path for a store-signed iPhone IPA, and for an Expo-signed Android production build, without a macOS GitHub runner. Expo's servers compile iOS. GitHub only bills the Ubuntu minutes used to start the job and wait for Expo.
- In the unzipped project, run
npx eas-cli@latest loginandnpx eas-cli@latest init. Commit theextra.eas.projectIdExpo writes toapp.json. - Configure Apple signing in your Expo account with
npx eas-cli@latest credentials --platform ios, or by finishing one interactivenpm run build:production -- --platform ioson your machine. Non-interactive CI cannot complete Expo's credentials wizard. See Expo app credentials (opens in a new tab). - In the GitHub repository, add a repository secret named
EXPO_TOKENwith an access token from your Expo account. Never commit the token; the ZIP does not include one. See Expo programmatic access (opens in a new tab). - Open Actions and run EAS cloud build. For a store-signed iPhone IPA, leave the defaults: platform
iosand profileproduction. You can also chooseandroidorall, and any profile already in this ZIP'seas.json(production,preview,development, orios-simulator). Theios-simulatorprofile is iOS only and is not an iPhone IPA. Thedevelopmentprofile needsnpm run setup:developmentcommitted first. - Open the Expo build URL printed in the job log and download the IPA (or Android artifact) from Expo. Xyvenra does not run, receive, or pay for the build. This workflow does not submit to TestFlight, the App Store, or Google Play.
The job fails before calling EAS if EXPO_TOKEN is missing, the project is not linked, or you pick a profile that is not in eas.json. An Apple Developer Program membership (US$99 a year) is required for an iPhone IPA, TestFlight, or App Store upload. Google Play publishing still needs your own Play developer account and the closed-test rules described above.
Submit a store-signed IPA to TestFlight
xyvenra-eas-submit-testflight.yml is the iOS counterpart to the Play internal-testing draft upload. It is a separate, optional workflow: xyvenra-eas-build.yml still only builds. Starting a build does not submit the IPA. The job runs official eas submit --non-interactive on Ubuntu. Expo Submit works on macOS, Linux, and Windows (opens in a new tab), so this does not need a macOS GitHub runner. It uploads a finished store-signed iOS production IPA to TestFlight in your App Store Connect account. It does not submit the app for App Store review and has no production or App Store release option. A TestFlight build is not released on the App Store (opens in a new tab); you start that submission yourself in App Store Connect when you are ready. You create the first App Store Connect listing yourself. Xyvenra does not run, receive, hold the App Store Connect API key, or pay for the submit. Expo bills the Expo account that owns the token. GitHub bills the Ubuntu minutes used to start the job.
Before you run it:
- Enroll in the Apple Developer Program (opens in a new tab) (US$99 a year) and create the first App Store Connect listing for the app. The workflow needs that listing's numeric Apple ID (
ASC_APP_IDin App Store Connect under App Information). - Link the project and finish a store-signed iOS production build, for example by running EAS cloud build with platform
iosand profileproduction. Simulator, preview, and development builds cannot be submitted to TestFlight. - Create an App Store Connect API key (opens in a new tab). An Account Holder or Admin role can create the key. Download the
.p8file once and store it privately.
In the GitHub repository, add these repository secrets. The first names follow Expo's official CI and eas.json environment names, documented in Submit to Apple (opens in a new tab) and the eas.json reference (opens in a new tab):
| Secret or env name | What it is |
|---|---|
EXPO_TOKEN | Official Expo CI token name. An access token from your Expo account. |
ASC_API_KEY_ID | Official eas.json ascApiKeyId environment name ($ASC_API_KEY_ID). The Key ID of the App Store Connect API key. |
ASC_API_KEY_ISSUER_ID | Official eas.json ascApiKeyIssuerId environment name ($ASC_API_KEY_ISSUER_ID). The Issuer ID of that key. |
ASC_API_KEY_PATH | Official eas.json ascApiKeyPath environment name ($ASC_API_KEY_PATH). A file path, not a GitHub secret. The job writes this path from the ASC_API_KEY_P8 secret. |
ASC_API_KEY_P8 | The full contents of the API key .p8 file. Official Expo docs take a path, so this extra secret holds the file contents for GitHub Actions. |
ASC_APP_ID | The numeric Apple ID of your App Store Connect listing (ascAppId). Required for non-interactive submit. |
Never commit the token or the .p8 file; the ZIP does not include them. Expo can also use an App Store Connect API key already assigned to the app in your Expo account (eas credentials --platform ios, then set up an API key for Expo Submit). With --non-interactive, eas submit uses that stored key if you do not bring your own credentials, and it fails if no key is assigned. This workflow does not take that implicit path: it still requires the GitHub secrets above and fails closed if they are missing or invalid, if the project is not linked, or if there is no finished store-signed iOS production build.
Then open Actions and run Submit to TestFlight. Leave build_id empty to use the latest finished store-signed iOS production build, or paste an EAS build ID. The job fails before calling eas submit if a secret is missing or malformed, extra.eas.projectId is missing, or the selected build is missing, still running, a Simulator build, or a preview or development build. The .p8 file is written into the runner's temporary directory and deleted before the job finishes, including on failure. The job never prints the token or the .p8 contents.
After Apple processes the upload (often 10-15 minutes), the build appears in TestFlight. Add internal testers in App Store Connect. If App Store Connect holds the build for export compliance, answer that question there; this workflow does not set ios.config.usesNonExemptEncryption for you. External TestFlight testing and App Store review stay manual in App Store Connect.
Store-signed builds from your own machine
You can start the same store-signed builds from the Expo CLI with your own Apple Developer Program membership (US$99 a year) and Google Play developer account; Expo bills your Expo account. Or run npx eas-cli@latest build --local --platform android (or ios on a Mac) on a machine you control after linking the project. Local builds run on your hardware; you install the required Android SDK, Xcode, CocoaPods, and fastlane. See Expo local builds (opens in a new tab). An iPhone build or App Store upload always needs your Apple Developer Program membership and signing.
Build and run an iOS Simulator preview
The project ZIP includes an ios-simulator EAS profile and a manual .eas/workflows/ios-simulator-preview.yml. After installing dependencies, signing in to your Expo account, and linking the project, run npm run build:ios-simulator to build directly or npm run workflow:ios-simulator-preview to run its Expo Workflow. The profile sets ios.simulator: true, so EAS can build it without Apple Developer enrollment or Apple signing credentials. Expo's build allowance and any account limits still apply.
To install the finished build, use a Mac with Xcode and an iOS Simulator, then run npm run run:ios-simulator and select the build. The simulator app is for desktop simulator testing; it cannot be installed on an iPhone or submitted to the App Store. See Expo's iOS Simulator build guide (opens in a new tab).
Run the Android preview workflow
The downloaded ZIP includes .eas/workflows/android-preview.yml. From the extracted project, sign in with npx eas-cli@latest login, link the project and keep the existing profiles as described above. Set up its Android signing keystore using npx eas-cli@latest credentials --platform android and select the preview profile. Then run npm run workflow:android-preview and follow the run URL to the APK. A manual CLI run uploads the local project to Expo and works without linking GitHub. Review your source and seed data before uploading.
The workflow runs one Android job with the internal APK profile. It starts on explicit invocation and uses your Expo account's limits. Expo serves the build logs and APK. Check the project's internal-build access settings before sharing the install link. See the Expo Workflows guide (opens in a new tab).
Check workflow status in your Expo project
Optional saved Viewer connection
If the operator enables saved Expo connections, a signed-in customer can connect one Expo account/project for read-only run checks. In Expo, create a personal access token limited to Only selected accounts and the Viewer role for the account that owns the project. Expo's documented token scopes are account roles, so use a dedicated token and revoke it in Expo when no longer needed. Provide an existing workflow run ID from that project to verify the token and project slug before saving. Xyvenra encrypts the token on the server with AES-256-GCM; the browser receives only the project slug and bounded run/build details. Replace the connection by verifying a new token and run. Removing a connection deletes Xyvenra's copy; revoke the token separately in Expo. The connection holds no project UUID and does not authorize build dispatch. The browser-only, request-only checker below remains available.
Deployment setup: apply 20261108170836_xyvenra_mobile_expo_connections.sql on the existing Supabase project, then set a dedicated server-only XYVENRA_MOBILE_EXPO_CREDENTIAL_KEY to 32 random bytes encoded as standard Base64. Keep it out of source and client variables. During rotation, set the new key as XYVENRA_MOBILE_EXPO_CREDENTIAL_KEY and the old key as XYVENRA_MOBILE_EXPO_CREDENTIAL_PREVIOUS_KEY; successful saved-run checks re-encrypt with the new key. Keep the previous key until every connection has been replaced or read and rotated. The database stores ciphertext in a service-role-only table with RLS; authenticated clients have no table grants. Connect and saved-run requests are limited to 4 KB and ten requests per account per minute. Without the key or migration, the saved-connection panel stays hidden. This setup uses the existing Supabase project and adds no paid infrastructure.
Expo documents OAuth for its hosted MCP server, but does not document an OAuth grant for Xyvenra to link customer accounts. Its public Workflows REST API cannot read a project's UUID and slug together, so Xyvenra cannot safely verify a customer-entered UUID before dispatch. Xyvenra therefore does not link or verify Expo accounts on the customer's behalf. The token-based dispatch described at the top of this page forwards your token, project UUID, commit, and workflow file to Expo for that one request; Expo checks access and bills your Expo account. You can also run the generated project's CLI workflow directly in your own Expo account. See Expo programmatic access (opens in a new tab), Expo MCP authentication (opens in a new tab), and Workflows REST API (opens in a new tab).
The Mobile workspace also lets any signed-in Xyvenra user check one workflow run in an Expo project they can access. Enter the project slug as account/project, the workflow run ID, and an Expo access token. Create a token with access limited to the selected account and the Viewer role where Expo supports it. Read the run ID from its workflow URL in Expo. Xyvenra forwards the token to Expo for this read-only request, checks that the returned run belongs to the project slug you entered, and discards the request after the response. The token is held in page memory only and is cleared on reload or when you leave the page. Use a temporary, narrowly scoped token and revoke it in Expo when finished. The checker reports workflow and job states and links to Expo-hosted build details. It does not queue a workflow, retrieve build files, retain credentials, or save the project link. See Expo's Workflows REST API (opens in a new tab) and programmatic access guide (opens in a new tab).
Track a workflow in Xyvenra
The optional Expo workflow status panel is a pilot for one Xyvenra operator and one Expo project. Paste a run ID from the end of its Expo workflow URL to see current run and job status. The panel shows a validated source commit hash when Expo includes one, remembers the last valid run ID in the current tab's session storage, and restores it after a reload in that tab; choose Check run to refresh the restored run, then Check again for later refreshes. The run ID stays in that browser session, is not synced to your account, and is not an Expo credential. Open the linked Expo run for logs or the build page for the APK. Status checks use the Expo API. Build execution and artifact access are managed by Expo.
Xyvenra keeps the Expo build-details link for logs and exposes a separate Download Android APK link only when a signed EAS build webhook matches the pinned Expo app, project, Android platform, source commit, reserved workflow run, successful job, and build ID. The project-wide Android webhook accepts only the preview profile with internal distribution, and only an HTTPS APK URL from Expo's expo.dev/artifacts/eas/ path; production, development, store-distribution, and other profile events are acknowledged without changing the preview record. Xyvenra does not proxy or retain the artifact. Expo controls access and retention. Its webhook signature is HMAC-SHA1 over the raw request body, carried in expo-signature; Xyvenra verifies it before parsing or storing the bounded allowlist fields. Expo retries deliveries that receive non-2xx responses. See the Workflows REST API (opens in a new tab), EAS webhooks (opens in a new tab), and Expo data retention (opens in a new tab).
To enable the panel, add these server-side deployment settings and redeploy:
XYVENRA_MOBILE_EXPO_OPERATOR_IDis the authorized Xyvenra account's Supabase user UUID.XYVENRA_MOBILE_EXPO_PROJECTis the Expo account and project slug inaccount/projectform, as shown in the Expo dashboard URL.XYVENRA_MOBILE_EXPO_TOKENis a read-only Expo access token for the project's runs. Create a robot user with the Viewer role on the owning account, create its token, and enter it directly as a server-side deployment secret. A Viewer can inspect runs but cannot dispatch builds.
The panel is hidden until all three settings are valid and the operator signs in. To verify setup, paste the ID of an existing run from that Expo project. The panel checks one run at a time and does not retain a run history. This is one operator-linked Expo project, not customer self-service account linking. Keep the configured Expo account/project slug and project UUID paired to the same project. See Expo Workflows REST API (opens in a new tab) and Expo token permissions (opens in a new tab).
Queue a configured Android preview
Operators can optionally enable Queue configured Android preview for one reviewed source revision. Connect the Expo project to a repository containing the extracted Mobile project at its root and the generated .eas/workflows/android-preview.yml. Set up Android signing in Expo. The idempotent dispatch-reservation migration creates a table keyed by the configured Expo project UUID and pinned commit SHA; RLS is enabled, client roles have no table privileges, and only service_role can use it.
Alongside the read-only monitor settings, configure XYVENRA_MOBILE_EXPO_PROJECT_ID with the linked Expo project UUID and XYVENRA_MOBILE_EXPO_PREVIEW_COMMIT with the reviewed 40-character commit SHA. For dispatch, create a separate robot user and token with the Developer role, the lowest Expo account role that can start builds, and store its token as the server-side XYVENRA_MOBILE_EXPO_DISPATCH_TOKEN secret. The dispatch token is not the Viewer token. Redeploy to pick up these settings. The button sends only the pinned commit and fixed Android preview workflow to Expo, using the owning account's build allowance. Expo's REST endpoint still authorizes that token at the account/project level; Xyvenra constrains the request in its own server code.
Xyvenra reserves one active attempt per project, workflow type, and commit. A repeat returns the recorded run when available. If Expo definitively rejects a dispatch, Xyvenra releases that reservation so it can be tried again. An ambiguous network/provider response keeps the reservation; check Expo Workflows before asking an administrator to clear it. After checking a failed or canceled pinned run, the operator can use the explicit retry action. Xyvenra verifies the run belongs to the configured Expo project and pinned commit, resets that attempt's status/artifact fields atomically, and sends the same fixed workflow again. The panel then tracks only the latest attempt; earlier runs remain in Expo. Successful builds cannot be retried from this control.
The production operator pilot is configured for one Expo project and a pinned GitHub revision. On November 8, 2026, the live Xyvenra button dispatched that revision, Expo built the Android preview APK successfully, and the signed-in status panel reported the successful workflow and linked Expo build details. Direct artifact links require the webhook setup below and are only shown for the pinned run and matching completed build. This does not enable customer-selected projects or builds.
Dispatch and track an iOS Simulator build in Xyvenra
The operator panel can queue the pinned iOS Simulator workflow alongside Android by setting the server-only XYVENRA_MOBILE_EXPO_IOS_SIMULATOR_ENABLED=true. It reuses the existing operator allowlist, Expo project, pinned commit, and separate Developer-role dispatch token. Simulator runs use their own idempotency reservation so they do not block or reuse the Android run for the same commit. Apply migration 20261108130354_xyvenra_mobile_ios_simulator_dispatches.sql before deploying this panel change. The iOS workflow file must be present in the Expo-linked repository at the pinned commit; update the pinned reviewed commit only after both workflow files are in that repository. The panel sends a workflow dispatch only after the operator confirms, then uses the same run-ID status check and Expo build-details link as other workflows. The simulator artifact migration and signed webhook handling are deployed. The production iOS dispatch panel remains disabled while XYVENRA_MOBILE_EXPO_IOS_SIMULATOR_ENABLED is false; no simulator build was triggered by this deployment. If the panel is enabled, a completed iOS build can expose a direct Expo-hosted archive link only when the signed build event, configured project, pinned commit, iOS Simulator profile, reserved workflow run, and successful matching build job all agree.
The project-wide Expo BUILD webhook used for artifacts also receives other profiles and revisions. Xyvenra acknowledges correctly signed, out-of-scope events without changing either artifact record. For Android artifacts, an event must use the preview build profile with internal distribution. For simulator artifacts, the event must identify the pinned project and commit, use the ios-simulator build profile from the pinned Mobile workflow, and provide an Expo-hosted .tar.gz artifact. Before saving either artifact, Xyvenra uses the server-side Viewer token to confirm the build ID belongs to the currently reserved workflow run. This prevents a late webhook from an earlier retry from replacing the current attempt's artifact. Xyvenra does not queue or run a build automatically.
To roll back this dispatch capability, set XYVENRA_MOBILE_EXPO_IOS_SIMULATOR_ENABLED to false or remove it and redeploy. After old app code is no longer reading/writing the table, run drop table if exists public.xyvenra_mobile_expo_simulator_dispatches;. Android reservations and run records are unaffected.
Enable direct build artifact links
The production BUILD webhook is registered at https://xyvenra.com/api/mobile/expo-build-webhook. Its signing secret is stored in Vercel as XYVENRA_MOBILE_EXPO_WEBHOOK_SECRET and in Expo's webhook configuration; keep its value out of source files and logs. Vercel requires a deployment for environment changes to take effect.
Migration 20261108093002_xyvenra_mobile_expo_webhook_artifacts.sql enables Android APK links and was applied to production on November 8, 2026. Migration 20261108135315_xyvenra_mobile_ios_simulator_artifacts.sql adds a separate constrained simulator archive record. It was applied to production on November 8, 2026, before deploying this iOS artifact handling change. The webhook verifies Expo's raw-body HMAC-SHA1 signature before saving records. The status panel returns an artifact link only when the configured Expo project, pinned commit, dispatched workflow run, signed build ID, matching successful job, build profile, and strict Expo artifact URL allowlist all match. Android remains limited to .apk files at https://expo.dev/artifacts/eas/; simulator links are limited to .tar.gz files at that exact host and path. Xyvenra never proxies or stores the artifact bytes. Simulator archives require macOS and Xcode and cannot be installed on an iPhone.
To roll back iOS artifact links, deploy code without simulator artifact reads/writes, then drop the three added simulator artifact columns and constraints. Keep the project-wide webhook if Android artifact links are still needed.
The migration 20261108093002_xyvenra_mobile_expo_webhook_artifacts.sql adds nullable build ID, terminal build status, and constrained APK URL fields to the service-role-only dispatch reservation table. It was applied to the production database on November 8, 2026. To roll back: disable/delete the Expo webhook, deploy code without webhook reads/writes, then run alter table public.xyvenra_mobile_expo_dispatches drop constraint if exists xyvenra_mobile_expo_dispatches_artifact_status_check, drop constraint if exists xyvenra_mobile_expo_dispatches_artifact_url_check, drop constraint if exists xyvenra_mobile_expo_dispatches_build_status_check, drop column if exists expo_artifact_url, drop column if exists expo_build_status, drop column if exists expo_build_id;. Existing dispatch/run reservations are preserved.
Over-the-air updates
EAS Update publishes JavaScript and compatible asset changes. It cannot replace native code or add a native dependency to an installed binary. After the project is linked, configure updates once with the script included in the ZIP:
npx eas-cli@latest update:configure
Review the generated changes to app.json and package.json, then run npm install. Build and install new binaries for the configured update channels before publishing updates. For example:
npm run publish:update:production -- --message "release notes"
You can also use npm run publish:update:development -- --message "release notes" or npm run publish:update:preview -- --message "release notes". Publish only to a channel installed by your users' builds. EAS Update publishes JavaScript and compatible assets; it cannot replace native code or add a native dependency to an installed binary. Rebuild and redistribute the app for native changes. Expo account limits apply. See Expo's EAS Update setup guide (opens in a new tab) for how runtime versions and channels keep updates compatible with installed binaries.
Publish an EAS Update from your GitHub repository
The project ZIP includes .github/workflows/xyvenra-eas-update.yml. It is a separate, optional workflow: xyvenra-eas-build.yml still only builds, and xyvenra-eas-submit-testflight.yml still only submits to TestFlight. Starting a build or a TestFlight submit does not publish an update. The job runs official eas update --non-interactive on Ubuntu. EAS Update works on macOS, Linux, and Windows (opens in a new tab), so this does not need a macOS GitHub runner. It publishes a JavaScript and asset update to a channel in your Expo account. An OTA update cannot add native code or native dependencies. Publish only to a channel already installed by your users' builds. It does not submit to the App Store or Google Play. Xyvenra does not run, receive, or pay for this update. Expo bills the Expo account that owns the token. GitHub bills the Ubuntu minutes used to start the job.
This job does not run eas update:configure. After linking the project, run npm run configure:updates once locally, review the Expo changes to app.json (runtimeVersion and updates.url) and package.json (the expo-updates package), reinstall dependencies, commit them, and build and install new binaries for the channels you plan to update.
In the repository, create a secret named EXPO_TOKEN with an access token from your Expo account. Never commit the token. The ZIP does not include one.
Open Actions, choose Publish an EAS Update, and select Run workflow. Choose channel: development, preview, or production. The input does not default to production; pick the channel already installed by your users' builds. Enter a required message describing the JavaScript and asset change. Official Expo CLI for SDK 55 and later also requires --environment; this job passes the same value as the selected channel. The run stops if the token is missing or invalid, the channel is missing or not one of those three, the message is empty, the project is not linked (extra.eas.projectId), or EAS Update is not already configured. Expo account limits apply.
Roll back an EAS Update from your GitHub repository
The project ZIP includes .github/workflows/xyvenra-eas-update-rollback.yml. It is a separate, optional workflow: xyvenra-eas-update.yml still only publishes a new JavaScript and asset update from the current commit, xyvenra-eas-build.yml still only builds, and xyvenra-eas-submit-testflight.yml still only submits to TestFlight. Starting a publish, a build, or a TestFlight submit does not roll back an update. The job runs official eas update:republish --group --non-interactive or official eas update:roll-back-to-embedded --non-interactive on Ubuntu. EAS Update works on macOS, Linux, and Windows (opens in a new tab), so this does not need a macOS GitHub runner. It republishes a previous update, or publishes a directive that returns clients to the update embedded in their build, in your Expo account. It does not publish a new JavaScript bundle from this commit. It does not run the interactive eas update:rollback (opens in a new tab) guide, and it does not use eas update:republish --branch without a group, because that path is interactive. An OTA rollback cannot add native code or native dependencies. Users who already downloaded a bad update keep running it until they can download the rollback (opens in a new tab). It does not submit to the App Store or Google Play. Xyvenra does not run, receive, or pay for this rollback. Expo bills the Expo account that owns the token. GitHub bills the Ubuntu minutes used to start the job.
This job does not run eas update:configure. After linking the project, run npm run configure:updates once locally, review the Expo changes, reinstall dependencies, commit them, and build and install new binaries for the channels you plan to update before publishing or rolling back.
In the repository, create a secret named EXPO_TOKEN with an access token from your Expo account. Never commit the token. The ZIP does not include one.
Open Actions, choose Roll back an EAS Update, and select Run workflow. Choose action: republish or roll-back-to-embedded. For republish, enter the required group_id of a known-good previous update. For roll-back-to-embedded, choose channel (development, preview, or production) and enter the required runtime_version already installed by your users' builds. The channel input does not default to production. An optional message may describe the rollback. Official Expo CLI flags used here are --group, --channel, --runtime-version, --message, and --non-interactive; these commands do not take --environment. The run stops if the token is missing or invalid, the action is missing or not one of those two, a required input for that action is missing, the project is not linked (extra.eas.projectId), or EAS Update is not already configured. Expo account limits apply.
Pause or resume an EAS Update channel from your GitHub repository
The project ZIP includes .github/workflows/xyvenra-eas-channel-pause.yml. It is a separate, optional workflow: xyvenra-eas-update.yml still only publishes a new JavaScript and asset update from the current commit, xyvenra-eas-update-rollback.yml still only republishes a previous update or rolls back to the embedded update, xyvenra-eas-build.yml still only builds, and xyvenra-eas-submit-testflight.yml still only submits to TestFlight. Starting a publish, a rollback, a build, or a TestFlight submit does not pause or resume a channel. The job first runs official eas channel:view --non-interactive to confirm the named channel already exists, then official eas channel:pause --non-interactive or official eas channel:resume --non-interactive on Ubuntu. EAS Update works on macOS, Linux, and Windows (opens in a new tab), so this does not need a macOS GitHub runner. Pausing a channel in your Expo account stops Expo Update from serving updates to builds that check for updates on that channel (opens in a new tab). Clients keep running the update they already have. Resuming starts serving updates again, including any rollout in progress. This is not a rollback and does not publish a new JavaScript bundle from this commit. It does not run eas channel:create, eas update:configure, or the interactive channel picker (the job always passes the channel name). It does not submit to the App Store or Google Play. Xyvenra does not run, receive, or pay for this pause or resume. Expo bills the Expo account that owns the token. GitHub bills the Ubuntu minutes used to start the job. Expo account limits apply.
This job does not run eas update:configure or eas channel:create. After linking the project, run npm run configure:updates once locally, review the Expo changes, reinstall dependencies, commit them, and build and install new binaries for the channels you plan to update. The named channel must already exist.
In the repository, create a secret named EXPO_TOKEN with an access token from your Expo account. Never commit the token. The ZIP does not include one.
Open Actions, choose Pause or resume an EAS Update channel, and select Run workflow. Choose action: pause or resume. Choose channel (development, preview, or production). The channel input does not default to production. Official Expo CLI flags used here are the channel name and --non-interactive; these commands do not take --environment. The run stops if the token is missing or invalid, the action is missing or not one of those two, the channel is missing or not one of those three, the project is not linked (extra.eas.projectId), EAS Update is not already configured, or the named channel does not already exist.
Roll out an EAS Update from your GitHub repository
The project ZIP includes .github/workflows/xyvenra-eas-update-rollout.yml. It is a separate, optional workflow: xyvenra-eas-update.yml still only publishes a full (non-rollout) JavaScript and asset update from the current commit, xyvenra-eas-update-rollback.yml still only republishes a previous update or rolls back to the embedded update, xyvenra-eas-channel-pause.yml still only pauses or resumes a channel, xyvenra-eas-build.yml still only builds, and xyvenra-eas-submit-testflight.yml still only submits to TestFlight. Starting a publish, a rollback, a channel pause or resume, a build, or a TestFlight submit does not start, edit, or revert a rollout. The job runs official per-update rollouts on Ubuntu. EAS Update works on macOS, Linux, and Windows (opens in a new tab), so this does not need a macOS GitHub runner. eas update --channel --message --environment --rollout-percentage --non-interactive starts a JavaScript and asset update from this commit for a required percentage of users (opens in a new tab). eas update:edit [GROUPID] --rollout-percentage --non-interactive adjusts an existing rollout; 100 finishes it. eas update:revert-update-rollout --group --non-interactive restores the control update. A rollout only affects JavaScript and assets already publishable by EAS Update; it cannot add native code. This workflow does not treat an empty percentage as a full 100% publish; that belongs in the existing EAS Update publish workflow. Official eas update --rollout-percentage is an integer from 1 to 100; 0 is not a revert. This job does not run the interactive eas update:edit or eas update:revert-update-rollout pickers (those commands need a group ID here), does not use --branch or --channel without a group on those commands, and it does not run branch-based eas channel:rollout. It does not run eas update:configure or eas channel:create. It does not submit to the App Store or Google Play. Xyvenra does not run, receive, or pay for this rollout. Expo bills the Expo account that owns the token. GitHub bills the Ubuntu minutes used to start the job. Expo account limits apply.
This job does not run eas update:configure. After linking the project, run npm run configure:updates once locally, review the Expo changes, reinstall dependencies, commit them, and build and install new binaries for the channels you plan to update. A rollout cannot add native code or native dependencies.
In the repository, create a secret named EXPO_TOKEN with an access token from your Expo account. Never commit the token. The ZIP does not include one.
Open Actions, choose Roll out an EAS Update, and select Run workflow. Choose action: start, edit, or revert. For start, choose channel (development, preview, or production), enter a required message, and enter a required rollout_percentage from 1 to 100. The channel input does not default to production. Official Expo CLI flags used to start a rollout are --channel, --message, --environment, --rollout-percentage, and --non-interactive. For edit, enter the required group_id of the existing rollout and a required rollout_percentage from 1 to 100 (100 finishes the rollout). Official flags used to edit are the group ID, --rollout-percentage, and --non-interactive; eas update:edit does not take --environment. For revert, enter the required group_id; an optional message may describe the revert. Official flags used to revert are --group, optional --message, and --non-interactive; eas update:revert-update-rollout does not take --environment. The run stops if the token is missing or invalid, the action is missing or not one of those three, a required input for that action is missing or invalid, the project is not linked (extra.eas.projectId), or EAS Update is not already configured.
Check EAS release readiness from your GitHub repository
The project ZIP includes .github/workflows/xyvenra-eas-release-preflight.yml. It is a separate, optional workflow: xyvenra-eas-update.yml still only publishes a full (non-rollout) JavaScript and asset update from the current commit, xyvenra-eas-update-rollback.yml still only republishes a previous update or rolls back to the embedded update, xyvenra-eas-channel-pause.yml still only pauses or resumes a channel, xyvenra-eas-update-rollout.yml still only starts, edits, or reverts a per-update rollout, xyvenra-eas-build.yml still only builds, and xyvenra-eas-submit-testflight.yml still only submits to TestFlight. Starting a publish, a rollback, a channel pause or resume, a rollout, a build, or a TestFlight submit does not start this preflight, and this preflight does not start those jobs. The job runs official readiness checks on Ubuntu. Expo Doctor (opens in a new tab) works on Linux, so this does not need a macOS GitHub runner. Official commands used here are eas whoami, eas project:info (only after the local check has already confirmed extra.eas.projectId), eas config --platform --profile --non-interactive, and pinned npx --yes expo-doctor@1.21.8. Official eas config defaults to production if --profile is omitted, so this job always passes the selected profile and platform. Official eas whoami and eas project:info have no --non-interactive flag; this job does not invent one. GitHub Actions already sets CI, which official Expo CLI docs say disables interactive functionality. This check does not start eas build, eas submit, eas update, a channel pause or resume, or a rollout. It does not run eas update:configure, and it does not run eas channel:create. Official eas credentials has no --non-interactive flag and can manage or create credentials, so this job does not run that wizard, does not run eas credentials:configure-build, and does not invent a credentials probe. Non-interactive CI cannot finish Expo's credentials wizard; add Apple credentials in your own Expo account before the first store-signed iOS cloud build. This job cannot create those credentials. Xyvenra does not run, receive, or pay for this preflight. Expo bills the Expo account that owns the token if you later start a build or update. GitHub bills the Ubuntu minutes used to start the job. Expo account limits apply.
This job does not run eas update:configure. The project must already be linked (extra.eas.projectId). If you turn on check_updates, EAS Update must already be configured; this job still does not run eas update:configure.
In the repository, create a secret named EXPO_TOKEN with an access token from your Expo account. Never commit the token. The ZIP does not include one.
Open Actions, choose Check EAS release readiness, and select Run workflow. Choose platform: android, ios, or all. Choose profile: development, preview, production, or ios-simulator. The platform input does not default to a production submit or a production publish, and the profile input does not default to production. ios-simulator is only valid with platform ios. Optionally turn on check_updates to also fail closed if EAS Update is not already configured; leave it off unless you are checking update readiness. Official Expo CLI flags used to inspect the selected profile are --platform, --profile, and --non-interactive. The run stops if the token is missing or invalid, the platform or profile is missing or not one of those choices, or the project is not linked. If check_updates is on, it also stops when EAS Update is not already configured.
Check EAS build status from your GitHub repository
The project ZIP includes .github/workflows/xyvenra-eas-build-status.yml. It is a separate, optional workflow: xyvenra-eas-build.yml still only starts an EAS cloud build, xyvenra-eas-submit-testflight.yml still only submits to TestFlight, xyvenra-android-play-upload.yml still only uploads a Play internal-testing draft, xyvenra-eas-update.yml still only publishes a full (non-rollout) JavaScript and asset update, xyvenra-eas-update-rollback.yml still only republishes a previous update or rolls back to the embedded update, xyvenra-eas-channel-pause.yml still only pauses or resumes a channel, xyvenra-eas-update-rollout.yml still only starts, edits, or reverts a per-update rollout, and xyvenra-eas-release-preflight.yml still only checks release readiness. Starting a build, a TestFlight submit, a Play draft upload, a publish, a rollback, a channel pause or resume, a rollout, or a preflight does not start this job, and this job does not start those. The job runs official status commands on Ubuntu. EAS Build list, view, download, and cancel work on Linux, so this does not need a macOS GitHub runner. Official commands used here are eas build:list --non-interactive, eas build:view [BUILD_ID] with optional official --json (official help does not list --non-interactive on that command, so this job does not invent one), eas build:download --build-id --non-interactive, and eas build:cancel [BUILD_ID] --non-interactive. Official eas build:download is for simulator or emulator builds only. Store-signed iOS IPAs stay on Expo; use the existing TestFlight submit workflow. Play AABs use the existing Play draft-upload workflow. Official --build-id is mutually exclusive with --fingerprint, --platform, and --dev-client; this job passes only --build-id (and optional official --all-artifacts) when downloading. Without --all-artifacts, official eas build:download downloads only the application archive and errors if that archive is missing. A successful download is attached as a GitHub Actions artifact in your own repository. This job does not start eas build. Cancel only cancels the named build in your own Expo account and may stop an in-progress build you already started. Official non-interactive cancel requires a build ID; this job does not pass --platform or --profile together with a build ID, and it does not open an interactive picker. Xyvenra does not run, receive, or pay for this job. Expo bills the Expo account that owns the token. GitHub bills the Ubuntu minutes used to start the job. Expo account limits apply.
The project must already be linked (extra.eas.projectId).
In the repository, create a secret named EXPO_TOKEN with an access token from your Expo account. Never commit the token. The ZIP does not include one.
Open Actions, choose Check EAS build status, and select Run workflow. Choose action: list, view, download, or cancel. The action input defaults to list and does not default to cancel. For list, you may optionally set official filters platform (android, ios, or all), status (new, in-queue, in-progress, pending-cancel, errored, finished, or canceled), build_profile, limit (official default 10, cap 50), and json. Official list flags used when those inputs are filled are --platform, --status, --build-profile, --limit, --json, and always --non-interactive. For view, enter the required build_id; official flags used are the build ID and optional --json. For download, enter the required build_id; official flags used are --build-id and --non-interactive, plus optional --all-artifacts. For cancel, enter the required build_id; official flags used are the build ID and --non-interactive. The run stops if the token is missing or invalid, the action is missing or not one of those four, a required build ID is missing, an optional list filter is invalid, or the project is not linked.
Generate or compare EAS fingerprints from your GitHub repository
The project ZIP includes .github/workflows/xyvenra-eas-fingerprint.yml. It is a separate, optional workflow: xyvenra-eas-build.yml still only starts an EAS cloud build, xyvenra-eas-submit-testflight.yml still only submits to TestFlight, xyvenra-android-play-upload.yml still only uploads a Play internal-testing draft, xyvenra-eas-update.yml still only publishes a full (non-rollout) JavaScript and asset update, xyvenra-eas-update-rollback.yml still only republishes a previous update or rolls back to the embedded update, xyvenra-eas-channel-pause.yml still only pauses or resumes a channel, xyvenra-eas-update-rollout.yml still only starts, edits, or reverts a per-update rollout, xyvenra-eas-release-preflight.yml still only checks release readiness, and xyvenra-eas-build-status.yml still only lists, views, downloads, or cancels an existing build. Starting a build, a TestFlight submit, a Play draft upload, a publish, a rollback, a channel pause or resume, a rollout, a preflight, or a build-status job does not start this job, and this job does not start those. The job runs official fingerprint commands on Ubuntu. Official fingerprint commands work on Linux, so this does not need a macOS GitHub runner. Official commands used here are eas fingerprint:generate --non-interactive and eas fingerprint:compare --non-interactive. Official generate accepts --platform android or ios, optional --environment or optional --build-profile (-e), and optional --json. Official usage marks --environment and --build-profile as mutually exclusive. This job does not invent a platform default or an environment default, especially not production. Official non-interactive generate without --platform is ambiguous, so platform is required. Official compare needs at least one documented target: a hash versus the local project, two hashes, a build ID versus the local project, two build IDs, a build ID and an update ID, or a hash and an update ID. This job never runs compare with no targets and never passes --open. Official --environment on compare is only for when a fingerprint is generated from the local directory. A fingerprint is a hash of your project for use in determining compatibility between the native layer and JavaScript layer of your app (opens in a new tab). A matching fingerprint may mean the native layer is unchanged, so you may be able to reuse an existing native build and publish a JavaScript update instead. This job does not decide that for you, and it does not start eas build or eas update. Xyvenra does not run, receive, or pay for this job. Expo bills the Expo account that owns the token. GitHub bills the Ubuntu minutes used to start the job. Expo account limits apply.
The project must already be linked (extra.eas.projectId).
In the repository, create a secret named EXPO_TOKEN with an access token from your Expo account. Never commit the token. The ZIP does not include one.
Open Actions, choose Generate or compare EAS fingerprints, and select Run workflow. Choose action: generate or compare. The action input defaults to generate and does not default to an untargeted compare. For generate, enter the required platform (android or ios). You may optionally set official environment or official build_profile, but not both, and optional json. Official generate flags used when those inputs are filled are --platform, --environment or --build-profile, --json, and always --non-interactive. For compare, provide at least one official combination: hash1 versus the local project, hash1 and hash2, build_id versus the local project, build_id and build_id_2, build_id and update_id, or hash1 and update_id. Leave environment empty unless the comparison uses the local project. Official compare flags used when those inputs are filled are the hashes, --build-id, --update-id, optional --environment only for a local comparison, optional --json, and always --non-interactive. The run stops if the token is missing or invalid, the action is missing or not one of those two, a required generate platform is missing or invalid, both --environment and --build-profile are set on generate, compare has no documented targets, a combination is invalid, or the project is not linked.
Check EAS Update status from your GitHub repository
The project ZIP includes .github/workflows/xyvenra-eas-update-status.yml. It is a separate, optional workflow: xyvenra-eas-build.yml still only starts an EAS cloud build, xyvenra-eas-submit-testflight.yml still only submits to TestFlight, xyvenra-android-play-upload.yml still only uploads a Play internal-testing draft, xyvenra-eas-update.yml still only publishes a full (non-rollout) JavaScript and asset update, xyvenra-eas-update-rollback.yml still only republishes a previous update or rolls back to the embedded update, xyvenra-eas-channel-pause.yml still only pauses or resumes a channel, xyvenra-eas-update-rollout.yml still only starts, edits, or reverts a per-update rollout, xyvenra-eas-release-preflight.yml still only checks release readiness, xyvenra-eas-build-status.yml still only lists, views, downloads, or cancels an existing build, and xyvenra-eas-fingerprint.yml still only generates or compares fingerprints. Starting a build, a TestFlight submit, a Play draft upload, a publish, a rollback, a channel pause or resume, a rollout, a preflight, a build-status job, or a fingerprint job does not start this job, and this job does not start those. The job runs official Update status commands on Ubuntu. Official EAS Update list, view, and insights commands work on Linux, so this does not need a macOS GitHub runner. Official commands used here are eas update:list --non-interactive, eas update:view [GROUPID] with optional official --insights, --days, --start, --end, and --json (official help does not list --non-interactive on that command, so this job does not invent one), and eas update:insights [GROUPID] --non-interactive. The action input defaults to list and does not default to delete or to an untargeted view or insights. Official non-interactive eas update:list without --branch or --all prompts for a branch and then fails with "Branch name may not be empty," so this job requires one of those official flags and does not invent a default branch or channel, especially not production. Official usage marks --branch and --all as mutually exclusive. Official --limit defaults to 25 and is capped at 50; this job passes --limit, --platform, --runtime-version, --offset, --json, --branch, or --all only when filled. Official --days defaults to 7 when used with insights and the flag is omitted, and is mutually exclusive with --start/--end. Official eas update:view --days, --start, and --end are only used with --insights. Official insights --platform is ios or android only; official help does not list all. This job does not start eas update, eas update:republish, eas update:roll-back-to-embedded, eas update:rollback, eas update:edit, eas update:revert-update-rollout, eas update:delete, eas update:configure, eas channel:create, eas channel:pause, a rollout, eas build, eas submit, or eas credentials. Xyvenra does not run, receive, or pay for this job. Expo bills the Expo account that owns the token. GitHub bills the Ubuntu minutes used to start the job. Expo account limits apply.
The project must already be linked (extra.eas.projectId).
In the repository, create a secret named EXPO_TOKEN with an access token from your Expo account. Never commit the token. The ZIP does not include one.
Open Actions, choose Check EAS Update status, and select Run workflow. Choose action: list, view, or insights. The action input defaults to list and does not default to delete or to an untargeted view or insights. For list, set official branch or turn on official all, but not both. You may optionally set official filters platform (android, ios, or all), runtime_version, offset, limit (official default 25, cap 50), and json. Official list flags used when those inputs are filled are --branch or --all, --platform, --runtime-version, --offset, --limit, --json, and always --non-interactive. For view and insights, enter the required group_id. For view, you may optionally turn on official insights and set official days, start, or end, and optional json. Official view flags used are the group ID, optional --insights, optional --days, --start, or --end only with --insights, and optional --json; official help does not list --non-interactive, so this job does not invent one. For insights, you may optionally set official platform (ios or android only), days, start, end, and json. Official insights flags used when those inputs are filled are the group ID, --platform, --days or --start/--end, --json, and always --non-interactive. Official --days defaults to 7 when used with insights and the flag is omitted, and is mutually exclusive with --start/--end. The run stops if the token is missing or invalid, the action is missing or not one of those three, list is missing --branch and --all, those flags are both set, a required group ID is missing, an optional filter is invalid, or the project is not linked.
Check EAS submit status from your GitHub repository
The project ZIP includes .github/workflows/xyvenra-eas-submit-status.yml. It is a separate, optional workflow: xyvenra-eas-build.yml still only starts an EAS cloud build, xyvenra-eas-submit-testflight.yml still only submits to TestFlight, xyvenra-android-play-upload.yml still only uploads a Play internal-testing draft, xyvenra-eas-update.yml still only publishes a full (non-rollout) JavaScript and asset update, xyvenra-eas-update-rollback.yml still only republishes a previous update or rolls back to the embedded update, xyvenra-eas-channel-pause.yml still only pauses or resumes a channel, xyvenra-eas-update-rollout.yml still only starts, edits, or reverts a per-update rollout, xyvenra-eas-release-preflight.yml still only checks release readiness, xyvenra-eas-build-status.yml still only lists, views, downloads, or cancels an existing build, xyvenra-eas-fingerprint.yml still only generates or compares fingerprints, and xyvenra-eas-update-status.yml still only lists, views, or inspects insights for published updates. Starting a build, a TestFlight submit, a Play draft upload, a publish, a rollback, a channel pause or resume, a rollout, a preflight, a build-status job, a fingerprint job, or an Update status job does not start this job, and this job does not start those. The job runs official submit status commands on Ubuntu. Official EAS submit list, view, and cancel commands work on Linux, so this does not need a macOS GitHub runner. Official commands used here are eas submit:list --non-interactive, eas submit:view [SUBMISSION_ID] with optional official --json (official help does not list --non-interactive on that command, so this job does not invent one), and eas submit:cancel [SUBMISSION_ID] --non-interactive. The action input defaults to list and does not default to cancel or to an untargeted view. Official --limit defaults to 10 and is capped at 50; this job passes --platform, --status, --offset, --limit, or --json only when filled. Official --status values are awaiting-build, in-queue, in-progress, finished, errored, or canceled. Official --platform values are android, ios, or all. This job does not invent a platform default. Official eas submit:view --platform shows the most recent submission for a platform when the ID is omitted; this job requires a submission ID and does not use that path, and it does not pass --platform together with a submission ID. Official --platform on cancel is only for filtering when the ID is not provided; this job never passes --platform with a submission ID and does not open a picker. This job does not start eas submit or eas build:submit, and it does not run eas submit:retry or eas submit:status. Retrying a failed submission starts another store submit. Official eas submit:status --profile defaults to production and needs an App Store Connect API key from the submit profile. Cancel only cancels the named submission in your own Expo account and may stop an in-progress submit you already started. This job does not start a new submit. Xyvenra does not run, receive, or pay for this job. This is not a hosted Xyvenra service. Expo bills the Expo account that owns the token. GitHub bills the Ubuntu minutes used to start the job. Expo account limits apply.
The project must already be linked (extra.eas.projectId).
In the repository, create a secret named EXPO_TOKEN with an access token from your Expo account. Never commit the token. The ZIP does not include one.
Open Actions, choose Check EAS submit status, and select Run workflow. Choose action: list, view, or cancel. The action input defaults to list and does not default to cancel or to an untargeted view. For list, you may optionally set official filters platform (android, ios, or all), status (awaiting-build, in-queue, in-progress, finished, errored, or canceled), offset, limit (official default 10, cap 50), and json. Official list flags used when those inputs are filled are --platform, --status, --offset, --limit, --json, and always --non-interactive. This job does not invent a platform default. For view and cancel, enter the required submission_id. Official view flags used are the submission ID and optional --json; official help does not list --non-interactive, so this job does not invent one. Official eas submit:view --platform is only for showing the most recent submission when the ID is omitted; this job requires a submission ID and does not pass --platform with one. Official cancel flags used are the submission ID and --non-interactive. Official --platform on cancel is only for filtering when the ID is omitted; this job never passes --platform with a submission ID and does not open a picker. Cancel only cancels the named submission in your own Expo account and may stop an in-progress submit you already started. The run stops if the token is missing or invalid, the action is missing or not one of those three, a required submission ID is missing, an optional list filter is invalid, or the project is not linked.
Check EAS channel status from your GitHub repository
The project ZIP includes .github/workflows/xyvenra-eas-channel-status.yml. It is a separate, optional workflow: xyvenra-eas-build.yml still only starts an EAS cloud build, xyvenra-eas-submit-testflight.yml still only submits to TestFlight, xyvenra-android-play-upload.yml still only uploads a Play internal-testing draft, xyvenra-eas-update.yml still only publishes a full (non-rollout) JavaScript and asset update, xyvenra-eas-update-rollback.yml still only republishes a previous update or rolls back to the embedded update, xyvenra-eas-channel-pause.yml still only pauses or resumes a channel, xyvenra-eas-update-rollout.yml still only starts, edits, or reverts a per-update rollout, xyvenra-eas-release-preflight.yml still only checks release readiness, xyvenra-eas-build-status.yml still only lists, views, downloads, or cancels an existing build, xyvenra-eas-fingerprint.yml still only generates or compares fingerprints, xyvenra-eas-update-status.yml still only lists, views, or inspects insights for published updates, and xyvenra-eas-submit-status.yml still only lists, views, or cancels submissions. Starting a build, a TestFlight submit, a Play draft upload, a publish, a rollback, a channel pause or resume, a rollout, a preflight, a build-status job, a fingerprint job, an Update status job, or a submit status job does not start this job, and this job does not start those. The job runs official channel status commands on Ubuntu. Official EAS channel list, view, and insights commands work on Linux, so this does not need a macOS GitHub runner. Official commands used here are eas channel:list --non-interactive, eas channel:view [NAME] --non-interactive with optional official --offset, --limit, and --json (Official help lists --non-interactive on view, so this job always passes it), and eas channel:insights --channel --runtime-version --non-interactive with optional official --days, --start, --end, and --json. The action input defaults to list and does not default to an untargeted view or insights. This job requires a channel name for view and insights and does not invent a default channel, especially not production. Official list --limit defaults to 10 and is capped at 25; official view --limit defaults to 50 and is capped at 100; official --offset defaults to 0. This job passes --offset, --limit, or --json only when filled. Official --days defaults to 7 when omitted and is mutually exclusive with --start/--end. Official help does not list --environment on eas channel:insights, so this job does not invent one. This job does not start eas channel:create, eas channel:delete, eas channel:edit, eas channel:protect, eas channel:unprotect, branch-based eas channel:rollout, eas channel:pause, or eas channel:resume, and it does not start a build, submit, or publish an update. Xyvenra does not run, receive, or pay for this job. This is not a hosted Xyvenra service. Expo bills the Expo account that owns the token. GitHub bills the Ubuntu minutes used to start the job. Expo account limits apply.
The project must already be linked (extra.eas.projectId).
In the repository, create a secret named EXPO_TOKEN with an access token from your Expo account. Never commit the token. The ZIP does not include one.
Open Actions, choose Check EAS channel status, and select Run workflow. Choose action: list, view, or insights. The action input defaults to list and does not default to an untargeted view or insights. For list, you may optionally set official filters offset, limit (official default 10, cap 25), and json. Official list flags used when those inputs are filled are --offset, --limit, --json, and always --non-interactive. For view, enter the required channel name. This job does not invent a default channel, especially not production. Official view flags used are the channel name, optional --offset, --limit (official default 50, cap 100), --json, and always --non-interactive. Official help lists --non-interactive on view, so this job always passes it. For insights, enter the required channel and runtime_version. You may optionally set official days, start, end, and json. Official insights flags used when those inputs are filled are --channel, --runtime-version, --days or --start/--end, --json, and always --non-interactive. Official --days defaults to 7 when the flag is omitted and is mutually exclusive with --start/--end. Official help does not list --environment on this command, so this job does not invent one. The run stops if the token is missing or invalid, the action is missing or not one of those three, a required channel name is missing, a required runtime version is missing, official --days is set together with --start or --end, an optional filter is invalid, or the project is not linked.
Check EAS branch status from your GitHub repository
The project ZIP includes .github/workflows/xyvenra-eas-branch-status.yml. It is a separate, optional workflow: xyvenra-eas-build.yml still only starts an EAS cloud build, xyvenra-eas-submit-testflight.yml still only submits to TestFlight, xyvenra-android-play-upload.yml still only uploads a Play internal-testing draft, xyvenra-eas-update.yml still only publishes a full (non-rollout) JavaScript and asset update, xyvenra-eas-update-rollback.yml still only republishes a previous update or rolls back to the embedded update, xyvenra-eas-channel-pause.yml still only pauses or resumes a channel, xyvenra-eas-update-rollout.yml still only starts, edits, or reverts a per-update rollout, xyvenra-eas-release-preflight.yml still only checks release readiness, xyvenra-eas-build-status.yml still only lists, views, downloads, or cancels an existing build, xyvenra-eas-fingerprint.yml still only generates or compares fingerprints, xyvenra-eas-update-status.yml still only lists, views, or inspects insights for published updates, xyvenra-eas-submit-status.yml still only lists, views, or cancels submissions, and xyvenra-eas-channel-status.yml still only lists, views, or inspects insights for channels. Starting a build, a TestFlight submit, a Play draft upload, a publish, a rollback, a channel pause or resume, a rollout, a preflight, a build-status job, a fingerprint job, an Update status job, a submit status job, or a channel status job does not start this job, and this job does not start those. The job runs official branch status commands on Ubuntu. Official EAS branch list and view commands work on Linux, so this does not need a macOS GitHub runner. Official commands used here are eas branch:list --non-interactive and eas branch:view [NAME] --non-interactive with optional official --offset, --limit, and --json (Official help lists --non-interactive on view, so this job always passes it). The action input defaults to list and does not default to an untargeted view. This job requires a branch name for view and does not invent a default branch, especially not production. Official list --limit defaults to 50 and is capped at 100; official view --limit defaults to 25 and is capped at 50; official --offset defaults to 0. This job passes --offset, --limit, or --json only when filled. This job does not start eas branch:create, eas branch:delete, or eas branch:rename, and it does not start a build, submit, or publish an update. Xyvenra does not run, receive, or pay for this job. This is not a hosted Xyvenra service. Expo bills the Expo account that owns the token. GitHub bills the Ubuntu minutes used to start the job. Expo account limits apply.
The project must already be linked (extra.eas.projectId).
In the repository, create a secret named EXPO_TOKEN with an access token from your Expo account. Never commit the token. The ZIP does not include one.
Open Actions, choose Check EAS branch status, and select Run workflow. Choose action: list or view. The action input defaults to list and does not default to an untargeted view. For list, you may optionally set official filters offset, limit (official default 50, cap 100), and json. Official list flags used when those inputs are filled are --offset, --limit, --json, and always --non-interactive. For view, enter the required branch name. This job does not invent a default branch, especially not production. Official view flags used are the branch name, optional --offset, --limit (official default 25, cap 50), --json, and always --non-interactive. Official help lists --non-interactive on view, so this job always passes it. The run stops if the token is missing or invalid, the action is missing or not one of those two, a required branch name is missing, an optional filter is invalid, or the project is not linked.
Costs and limits
Expo applies its current build and update quotas, plan limits, and charges to the developer's Expo account. Use the Expo CLI steps above to link the downloaded project, start builds, publish updates, or submit to the stores.