CI/CD integration
Run Maestro flows in GitHub Actions, GitLab CI, and CircleCI with Maestro Deck.
Maestro Deck flows are plain Maestro YAML, so any CI runner that can install the Maestro CLI and boot a simulator or emulator can execute them. This guide walks through GitHub Actions, GitLab CI, and CircleCI configurations and the gotchas each platform throws at you.
TL;DR
The recipe is the same on every provider: (1) check out the repo, (2) install the Maestro CLI at the version pinned in your project, (3) start a simulator (iOS) or emulator (Android), (4) install the app build under test, (5) run maestro test .maestro/. The differences are how each provider gives you a runtime with simulators or emulators.
GitHub Actions — iOS
GitHub-hosted macos-latest runners ship with Xcode and simulators preinstalled.
Pin a Maestro version in your repo (e.g. .maestro-version) and read it in the install step instead of fetching latest. Otherwise a CLI release can break PRs unrelated to your changes.
GitHub Actions — Android
Use reactivecircus/android-emulator-runner — it caches the AVD and avoids the 5-minute boot cost on every run.
GitLab CI
GitLab does not provide hosted macOS runners on the free tier. For Android, the shared Linux runners with KVM enabled work:
For iOS, register a self-hosted macOS runner. There is no hosted alternative.
CircleCI
CircleCI has first-party macOS executors and an Android machine image.
Reporting
maestro test writes a JUnit report when given --format junit --output report.xml. Upload it as a CI artifact and most providers will render a per-test view in the PR.
Couple this with --debug-output to capture per-step screenshots; you will need them when something fails on the runner but not on your laptop.
Sharding
For suites larger than ~30 flows, run shards in parallel:
Most CI providers expose a node index variable for matrix or parallelism builds. See the parallel execution guide for tradeoffs.
Common pitfalls
- Version drift. Always pin the CLI version.
curl … | bashwithout a version pin defaults to latest and turns a stable suite into a coin flip. - Emulator readiness.
adb wait-for-devicereturns before the launcher is interactive. Add amaestro testprecheck step or sleep 10s. - Disk space. Android emulators eat 10–20 GB. On free tiers you may have to clean caches between jobs.
- Network. If your app talks to a staging backend, lock down the URL via env var rather than baking it into the APK / IPA.