Expo Workflows: send every EAS build to testers with a custom job
· 7 min read
Expo Workflows runs your EAS jobs from YAML files in .eas/workflows/. A push to main can build a preview for iOS and Android, and each build gets its own internal distribution page on expo.dev. That is often enough for the team. When testers outside the team need a link that always opens the newest build, a password, an easy way to register their iPhone, or a place to send feedback, you can add one more job to the same workflow and send each build to AppForShare. This guide shows that job, explains what it costs in Workflows minutes, and lists the other ways to do the same thing.
Expo now also calls this product "Expo Workflows", next to "Expo Build (EAS Build)". The CLI is still eas-cli. Facts below were read in Expo's docs and on expo.dev/pricing on November 4, 2026.
What Expo Workflows gives you
A workflow file lists jobs. Expo's pre-packaged jobs cover build, submit, testflight, update, fingerprint, maestro, slack, email, github-comment (for sharing test builds with QR codes on a pull request), apple-device-registration-request, require-approval and more. Workflows can start on GitHub events, by hand, or on App Store Connect events.
When no pre-packaged job does what you need, a custom job runs steps, either shell commands or built-in functions. The one that matters here is eas/download_build: you give it a build_id, it downloads the file (.apk, .aab, .ipa or .app) and hands the path to the next step as artifact_path (syntax docs). That is all you need to pass the build to another service.
Step 1: a build profile testers can install
Testers can only install builds made for internal distribution. On iOS that means an ad hoc build for registered iPhones. On Android, an APK installs directly; if you keep the .aab, AppForShare turns it into one APK testers install.
{
"build": {
"preview": {
"distribution": "internal",
"channel": "preview",
"android": { "buildType": "apk" }
}
}
}
Store builds cannot be installed from a link on either platform, so keep them in a separate profile.
Step 2: store the AppForShare token as an Expo secret
Uploads from CI use an API token from Dashboard, Settings, on Pro or Team. In your Expo project, add it as an environment variable named APPFORSHARE_TOKEN and mark it as a secret, so it never shows in logs. The CLI reads that variable by itself.
Step 3: add the share job
Save this as .eas/workflows/share-preview.yml. It builds both platforms on every push to main and sends each build to the Beta channel.
name: Share preview builds
on:
push:
branches: ['main']
jobs:
build_ios:
type: build
params:
platform: ios
profile: preview
build_android:
type: build
params:
platform: android
profile: preview
share_ios:
needs: [build_ios]
steps:
- uses: eas/download_build
id: download_build
with:
build_id: ${{ needs.build_ios.outputs.build_id }}
- run: npx --yes appforshare upload "${{ steps.download_build.outputs.artifact_path }}" --channel beta
share_android:
needs: [build_android]
steps:
- uses: eas/download_build
id: download_build
with:
build_id: ${{ needs.build_android.outputs.build_id }}
- run: npx --yes appforshare upload "${{ steps.download_build.outputs.artifact_path }}" --channel beta
The upload prints the install link of the build and the link of the channel. The channel is made on first use. When the iOS and Android projects are paired, one channel link sends iPhones to the iOS build and Android phones to the APK. Add --fail-on blocked if you want the job to fail when the store readiness check finds a blocker; the build stays uploaded either way.
What it costs in Workflows minutes
The build jobs bill as EAS builds. The share jobs are custom jobs, and they run on Expo's Workflows minutes, so they count toward your Expo plan. As listed on November 4, 2026, Expo prices Workflows minutes at $0.018 (medium) and $0.035 (large) per minute on Linux, and $0.075 and $0.150 on macOS. On the Free plan, Expo lists "up to 60 minutes" of CI/CD minutes: an allowance for Workflows jobs other than build jobs, such as this download and upload job, not a time limit per run (build jobs use the plan's included builds instead). Free plan limits reset monthly, and Free accounts cannot pay for more. A download and upload job takes a few minutes, a bit longer for large iOS builds. Recheck Expo's pricing page before you plan around these numbers. If you would rather not spend Workflows minutes at all, see the webhook option below.
What testers get from the AppForShare side
- One link that stays the same. The Beta channel link always opens the newest build put into it, and you can put an older build back if a release goes wrong (Pro). The EAS build page gives one URL per build.
- Control over who installs. A password per build on every plan, extra links with their own stop date and install cap on Pro, private projects and per tester access codes on Team. EAS internal links are open for anyone with the URL, or the project can require an Expo login.
- iPhone registration without an Apple ID sign in. Testers open the onboarding link on their iPhone, and an Admin registers the device on Apple with your App Store Connect API key (Pro). Then run
eas device:create, pick the Developer Portal import, and build again. - Expo facts and checks on each build. The build page shows the Expo SDK, runtime version and the update channel the build reads. The readiness check warns when a development client build goes to testers or when a test build reads your production update channel. This runs on every plan with an account.
- Feedback without an SDK. Testers send notes with screenshots from the install page.
Other ways to send EAS builds
| Way | Where it runs | Expo token needed | Plan |
|---|---|---|---|
| Workflows custom job (this guide) | Expo Workflows minutes | No, only the AppForShare token | Pro and Team |
| Connect Expo (EAS build webhook) | Nothing in your pipeline | No | Pro and Team |
upload --eas or --eas-latest | GitHub Actions, any CI, a laptop | Yes, stays on that machine | Pro and Team |
eas build --local, then upload | Your own machine | No | Pro and Team for the CLI, any plan from the web |
Connect Expo is the lightest. In the project you get a webhook address and a secret, and you run one command in your Expo project folder:
eas webhook:create --event BUILD \
--url https://appforshare.io/api/hooks/eas/<token> \
--secret <secret from AppForShare>
When an internal build finishes, AppForShare checks the expo-signature header, downloads the file from Expo and shares it, with release notes from the commit and a channel mapped from the build profile. Store builds are skipped with a note. See Connect Expo.
From GitHub Actions, npx appforshare upload --eas-latest --profile preview --platform ios --channel beta asks eas-cli on the runner for the newest finished build of that profile, downloads it and uploads it. With the GitHub Action and pr-comment: true, one comment on the pull request carries the iOS and Android links, QR codes and the readiness result, updated on each run. The full job is in the Expo EAS CI guide.
When the EAS page is enough
Be honest with yourself here. If your testers are a few developers who already have Expo accounts, if every iPhone is registered, and if a new link per build is fine, the expo.dev build page and Expo's own github-comment job may be all you need. Expo also has a pre-packaged testflight job with groups and What to Test notes, which is ahead of anything AppForShare runs inside Workflows. AppForShare pays off when testers are clients, QA vendors or people without accounts, and when you want feedback, readiness checks and store steps in one place. The full side by side is in AppForShare vs Expo EAS, and every option is in Use AppForShare with Expo EAS.
Related reading: what EAS Submit uploads and what you still do by hand, Expo EAS alternatives in 2026 and how to share a React Native build with testers.
More for EAS teams: how EAS internal distribution links work, keeping test builds off production updates and registering testers' iPhones with eas device:create.
Common questions
Does this replace EAS Build?
No. EAS keeps building, and EAS Update and EAS Submit keep working. The share job only takes the finished file.
Is my Expo token sent to AppForShare?
No. The Workflows job runs inside Expo and needs only the AppForShare token. Connect Expo needs no Expo token either.
Can I share only some builds?
Yes. Put the share job in a workflow that runs only on the branches you choose, or start it by hand.
Can testers install a production build from the link?
No. App Store and Google Play builds cannot be installed from a link. Share builds from an internal distribution profile.
To try it, create a free account, upload one EAS build from the web, and add the Workflows job when you move to Pro.


