Mobile CI with fastlane and GitHub Actions
Define your release once in a Fastfile and run the same lane locally and in CI.
fastlane wraps the messy parts of mobile release -- signing, building, uploading -- into named lanes you define once and run anywhere. In CI, your GitHub Actions job becomes a thin wrapper that invokes a lane, which keeps the build logic in version-controlled Ruby instead of YAML. This recipe runs a fastlane lane on a runner.
What the pipeline does
- Checks out the repo and installs the fastlane toolchain via Bundler.
- Runs a test lane defined in the Fastfile.
- Keeps build and release logic in the Fastfile, not the workflow.
- Runs the same lane developers use locally.
The workflow
Install fastlane through Bundler so the version is pinned in your Gemfile.lock and identical in CI and on laptops.
name: fastlane CI
on: [push, pull_request]
jobs:
test:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler-cache: true
- name: Run fastlane test lane
run: bundle exec fastlane test
env:
FASTLANE_HIDE_CHANGELOG: 'true'A matching Fastfile lane
The lane holds the real logic; the workflow just calls it.
# fastlane/Fastfile
default_platform(:ios)
platform :ios do
desc "Run unit tests"
lane :test do
run_tests(scheme: "MyApp")
end
endNotes for this platform
iOS lanes (run_tests, build_app) require a macos runner; Android-only lanes can run on Linux, so split platforms into separate jobs and only pay for macOS where you must. Use bundler-cache: true to cache gems between runs. Managed runners retry transient gem-install and upload failures automatically, which matters because fastlane lanes touch many flaky external services (App Store Connect, Play, signing).
Key takeaways
- fastlane keeps build and release logic in a version-controlled Fastfile, not YAML.
- Install fastlane via Bundler so CI and local use the same pinned version.
- Run Android lanes on Linux and only iOS lanes on macOS to limit cost.