Guide

Setting up fastlane on a dedicated Mac build server

On a Mac build server, install fastlane with Bundler, which fastlane prefers, or with Homebrew. Keep signing in match, run it readonly on CI, and log in to Apple with an App Store Connect API key. Start CI lanes with setup_ci, so fastlane uses a temporary keychain. Your CI job then runs one command: bundle exec fastlane beta.

What you need first

  • A Mac with Xcode, admin access and Homebrew.
  • A CI agent on that Mac: GitHub Actions, GitLab, Buildkite, Jenkins or CircleCI.
  • An App Store Connect account with the right to create API keys.
  • A private Git repo for match, or a Google Cloud or S3 bucket.

1. Install fastlane

fastlane's docs, read in October 2026, prefer Bundler. They support Ruby 3.2 or newer and prefer 3.3 or newer. They advise against macOS's system Ruby. Install a current Ruby with a version manager such as rbenv. Then add a Gemfile to the project:

source "https://rubygems.org"

gem "fastlane"
gem install bundler
bundle update
git add Gemfile Gemfile.lock

Bundler pins the fastlane version in Gemfile.lock. Every machine and every CI run gets the same one. Run it as bundle exec fastlane.

The simpler route on a single build server is Homebrew. It brings its own Ruby:

brew install fastlane

Pick one route per project. Mixing them is how two fastlane versions end up on one machine.

2. Create an App Store Connect API key

fastlane recommends API keys over Apple ID logins: no two-factor prompt, better speed, more reliability. In App Store Connect, open Users and Access, then Integrations, then App Store Connect API. Create a Team Key. fastlane notes that provisioning calls need a team key. Give it the smallest role that works. Note the Issuer ID and Key ID. Download the .p8 file right away, because Apple lets you download it only once.

mkdir -p ~/.appstoreconnect
mv ~/Downloads/AuthKey_ABC123XYZ.p8 ~/.appstoreconnect/
chmod 600 ~/.appstoreconnect/AuthKey_ABC123XYZ.p8

Keep the key on the build Mac or in your CI's secret store. Never commit it.

3. Set up match once, from a developer machine

bundle exec fastlane match init
bundle exec fastlane match development
bundle exec fastlane match appstore

match init asks where to store certificates and writes a Matchfile. The next two commands create certificates and profiles and save them, encrypted, to that storage. Choose a strong passphrase. CI reads it from the MATCH_PASSWORD variable.

fastlane recommends readonly mode on every CI system. Then CI only downloads what exists and never creates or revokes anything.

4. Write the lanes

default_platform(:ios)

platform :ios do
  lane :test do
    run_tests(
      scheme: "MyApp",
      devices: ["iPhone 17"],
      result_bundle: true
    )
  end

  lane :beta do
    setup_ci
    api_key = app_store_connect_api_key(
      key_id: ENV["ASC_KEY_ID"],
      issuer_id: ENV["ASC_ISSUER_ID"],
      key_filepath: ENV["ASC_KEY_PATH"]
    )
    match(type: "appstore", readonly: is_ci, api_key: api_key)
    increment_build_number(
      build_number: latest_testflight_build_number(api_key: api_key) + 1
    )
    build_app(scheme: "MyApp")
    upload_to_testflight(api_key: api_key, skip_waiting_for_build_processing: true)
  end
end

setup_ci creates a temporary keychain, switches match to readonly, and sets up log and test result paths. It acts only when fastlane detects a CI run. If yours is not detected, pass force: true. Skipping build processing ends the job sooner, but fastlane notes it also skips distribution to external testers.

5. Call it from CI

Every CI system runs the same shell lines. Store the secrets in your CI, not in the repo.

export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
bundle install
bundle exec fastlane beta
# needs MATCH_PASSWORD, ASC_KEY_ID, ASC_ISSUER_ID and ASC_KEY_PATH set as CI secrets

On GitHub Actions these lines go in a run step, with the secrets passed in as env. A MacRun Mac comes with the GitHub Actions runner software already installed. Our GitHub Actions iOS setup guide shows a full workflow. On GitLab, Buildkite or CircleCI, put the same lines in the job's script. On Jenkins, use an sh step.

How this survives reboots

fastlane is not a service. It runs inside your CI agent's job. What must survive a reboot is the agent and its login session. Set up the agent as a LaunchAgent with automatic login, as in our GitLab Runner and Buildkite guides. The temporary keychain from setup_ci is rebuilt on every run. A locked login keychain after a restart cannot stall it.

Common errors and fixes

These are documented by fastlane.

  • Odd encoding errors or crashes in CI. fastlane needs a UTF-8 locale. Set LANG and LC_ALL to en_US.UTF-8.
  • The job hangs at a two-factor prompt. Use the API key. With an Apple ID, set SPACESHIP_ONLY_ALLOW_INTERACTIVE_2FA so it fails fast instead.
  • match tries to create new certificates on CI. Use readonly, or call setup_ci first.
  • match cannot clone its repo. GitHub will not accept one deploy key on two repos. Use a read-only machine account, or git_private_key, or MATCH_GIT_BASIC_AUTHORIZATION.
  • Profiles are installed but Xcode cannot see them. Xcode 16 moved the profiles folder. fastlane follows the selected Xcode, so run xcode_select before match on machines with two Xcodes.

Why a dedicated Mac helps

build_app and run_tests are Xcode builds. On a machine that keeps DerivedData and installed gems, they are much faster. In our benchmark on the Wikipedia iOS app with Xcode 26.6, a clean build took 86 seconds on an M6. It took 183 seconds on a GitHub-hosted macos-26 runner. A job after a small change took 27 seconds warm, against 269 fresh.

When you do not need a build server

If you ship to TestFlight once a week, a hosted runner or Xcode Cloud is less work. See our Xcode Cloud alternative guide for that trade. Also note what MacRun does not do. We do not manage code signing for you. You run match yourself, as on this page. We also offer no SLA.

Ready for a build server? Pricing lists every tier, and the setup docs show how to connect.

Frequently asked questions

Should I install fastlane with Homebrew or Bundler on a build server?

+

fastlane prefers Bundler, because Gemfile.lock pins the version. Homebrew is simpler on a single machine and brings its own Ruby.

What does fastlane setup_ci do?

+

It creates a temporary keychain, switches match to readonly, and sets up log and test result paths. It only acts on CI unless you pass force: true.

Why use an App Store Connect API key with fastlane?

+

It needs no two-factor prompt, and fastlane calls it faster and more reliable than an Apple ID session. Create a Team Key for provisioning access.

Should match run in readonly mode on CI?

+

Yes. fastlane recommends it, so CI only downloads existing certificates and profiles and never creates or revokes them.

Related guides