EAS Workflows
The DeviceCloud EAS Workflow wrapper is a drop-in alternative to Expo's built-in maestro-cloud job type. Run your Maestro flows on DeviceCloud directly from your EAS Workflow — no need to leave your Expo pipeline.
Quick Start
jobs:
build_android:
type: build
params:
platform: android
profile: preview
e2e:
needs: [build_android]
runs_on: linux-medium
steps:
- uses: eas/checkout
- id: download
uses: eas/download_build
with:
build_id: ${{ needs.build_android.outputs.build_id }}
- id: dcd
run: |
npx --yes @devicecloud.dev/eas-workflow@v1 \
--app-file ${{ steps.download.outputs.artifact_path }} \
--flows ./.maestroBefore running, store your DeviceCloud API key as an EAS project secret:
You can find your API key in the DeviceCloud console settings.
Platform Examples
Android
iOS
Environment Variables
EAS context that doesn't change per-flow goes through the job-level env: block. Step-level env: may be silently ignored — keep env: on the job.
The wrapper turns these into either DCD flags or --metadata tags (so each run is searchable in the console).
Provided by EAS automatically
DEVICE_CLOUD_API_KEY
eas env:create --visibility secret
DCD --api-key (required). Auto-injected at runtime.
Build context (recommended)
DCD_EAS_BUILD_ID
${{ needs.<build_job>.outputs.build_id }}
eas_build_id metadata
DCD_EAS_PLATFORM
${{ needs.<build_job>.outputs.platform }}
eas_platform metadata
DCD_EAS_APP_VERSION
${{ needs.<build_job>.outputs.app_version }}
eas_app_version metadata
DCD_EAS_PROFILE
${{ needs.<build_job>.outputs.profile }}
eas_profile metadata
The build artifact itself is downloaded by eas/download_build and passed via --app-file — there is no build_url output on EAS Workflow build jobs.
Git context (optional)
DCD_GH_SHA
${{ github.sha }}
gh_sha metadata
DCD_GH_BRANCH
${{ github.ref_name }}
gh_branch metadata
DCD_GH_RUN_ID
${{ github.run_id }}
gh_run_id metadata
DCD_GH_PR_NUMBER
${{ github.event.pull_request.number }}
gh_pr_number metadata
DCD_GH_PR_URL
${{ github.event.pull_request.html_url }}
gh_pr_url metadata
DCD_GH_REPO
${{ github.repository }}
gh_repo metadata
DCD_CHECK_NAME
a fixed string, e.g. iOS
gh_check_name metadata — names the GitHub check this job posts (DeviceCloud / iOS)
Set DCD_CHECK_NAME when a commit is tested by more than one job, so each gets a check of its own that can be required separately in branch protection. Keep it fixed per job — GitHub matches required checks by name.
${{ github.event.pull_request.number }}, ${{ github.event.pull_request.html_url }} and ${{ github.repository }} resolve to null on manual triggers and EAS rejects them as invalid env values. Only set the PR and repo variables inside an if: guard that limits the job to PR events, or omit them. github.sha, github.ref_name and github.run_id coerce to empty strings safely.
Advanced
DEVICE_CLOUD_API_URL
https://api.devicecloud.dev
Override the API URL (staging/dev environments).
DCD_USE_BETA
false
Set to the string true to use the beta DCD CLI (any other value is treated as false).
DCD_EAS_BUILD_URL
—
Supply a build URL directly (mapped to dcd cloud --app-url) instead of downloading the artifact and passing --app-file. Useful when you host the binary yourself.
CLI Flags
Anything you pass on the command line after npx @devicecloud.dev/eas-workflow@v1 ... is forwarded verbatim to dcd cloud.
App source
--app-file <path>
Path to the downloaded build (typically ${{ steps.download.outputs.artifact_path }}).
--app-binary-id <id>
Reuse a previously uploaded binary instead of re-uploading.
--ignore-sha-check
Skip the duplicate-upload SHA check. Not recommended.
Flow Selection
--flows <path>
Path to a flow file or directory. Default: ./.maestro/.
--include-tags <tags>
Only run flows with these Maestro tags (comma-separated).
--exclude-tags <tags>
Exclude flows with these tags.
--exclude-flows <path>
Subdirectories to exclude.
--config <path>
Path to a custom Maestro config file.
Device Configuration
--android-device <model>
pixel-6, pixel-6-pro, pixel-7, pixel-7-pro.
--android-api-level <n>
29 – 37. Default 34 (36 from 19 October 2026).
--ios-device <model>
iphone-14, iphone-15, iphone-16, iphone-16-pro, iphone-16-pro-max, ipad-pro-6th-gen.
--ios-version <n>
17, 18, 26. Default 17.
--device-locale <code>
E.g. de_DE. See Device Locale.
--orientation <deg>
Android only. 0, 90, 180, 270.
--google-play
Android only. Run on Google Play devices.
--runner-type <type>
default, m1, m4. Non-default incurs premium pricing. See Runner Types.
See the Devices & OS Versions page for the full availability matrix.
Test Configuration
--maestro-version <semver>
Maestro CLI version. See Maestro Versions.
--env KEY=value
Inject environment variables into your flows. Repeatable.
--name <name>
Custom name for this test run.
--retry <n>
Number of automatic retries on failure (max 2). Retries are free.
--report <format>
junit, html, html-detailed, allure. See Report Formats.
Execution Options
--async
Exit immediately without waiting for results (exit code 0 regardless). See Async Execution.
--download-artifacts <mode>
Download logs/screenshots/videos. Options: ALL, FAILED.
--disable-animations
Disable device animations. See Animations.
--maestro-chrome-onboarding
Android only. See Chrome Onboarding.
--android-no-snapshot
Force cold boot. Auto-enabled for API 35+.
--debug
Verbose debug output.
Full CLI reference: CLI: Cloud.
Outputs
The wrapper emits these as EAS step outputs via set-output after the run completes.
console_url
URL to view the test results in the DeviceCloud console.
upload_status
Final status: PENDING, RUNNING, PASSED, FAILED, or CANCELLED.
flow_results
JSON array: [{ "name": "...", "status": "PASSED" }].
app_binary_id
ID of the uploaded binary. Reuse via --app-binary-id to skip re-upload.
Using outputs in a downstream job
Exit Codes
0
All flows passed, or run started successfully in async mode.
1
At least one flow failed, the run was cancelled, or the wrapper hit an internal error.
See Exit Codes for the full list.
Common Patterns
Run on every PR
Run async (non-blocking)
Pass secrets into flows
Set the secret as an EAS env var first:
Then reference it as a regular env var in the wrapper invocation:
Filter by tag
Migrating from maestro-cloud
EAS's built-in maestro-cloud job is closed-source and hardcoded to Maestro Cloud. To switch to DeviceCloud, replace the whole job with a custom job that calls the wrapper:
Then store your DeviceCloud API key as a project secret (as shown in Quick Start).
Source
The wrapper is open source and can be found here: github.com/devicecloud-dev/device-cloud-for-eas.
Last updated