Continuous Integration

Best Practices

Two-step or Two-factor auth

If you want to upload builds to TestFlight/iTunes Connect from your CI machine, you need to generate an application specific password:

  1. Visit
  2. Generate a new application specific password
  3. Provide the application specific password using the environment variable FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD

Because your CI machine will not be able to prompt you for your two-step or two-factor auth information, you also need to generate a login session for your CI machine in advance. You can get this by running:

fastlane spaceauth -u

This will generate a token you can set using the FASTLANE_SESSION environment variable on your CI system.

Environment variables to set

Most setups will need the following environment variables

  • FASTLANE_USER: Your iTunes Connect / Dev Portal user, if your fastlane setup accesses iTC or the DevPortal (e.g. submit a TestFlight build, create a profile, ...)
  • MATCH_PASSWORD: You need to provide the password of your match encryption if you use match
  • FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: You need to provide an application specific password if you have 2-factor enabled and use pilot or deliver to upload a binary to iTunes Connect

Deploy Strategy

You should not deploy a new App Store update after every commit, since you still have to wait 1-2 days for the review. Instead it is recommended that you use Git Tags, or custom triggers to deploy a new update.

You can set up your own Release job, which is only triggered manually.

Jenkins Integration

Deploying from your own computer isn't cool. You know what's cool? Letting a remote server publish app updates for you.

fastlane automatically generates a JUnit report for you. This allows Continuous Integration systems, like Jenkins, access the results of your deployment.


The recommended way to install Jenkins is through homebrew:

brew update && brew install jenkins

From now on start Jenkins by running:


To store the password in the Keychain of your remote machine, it is recommended that you run match or deliver using ssh or remote desktop at least once.

Ruby Environment

We recommend using rbenv for installing Ruby, though rvm and the version of Ruby that comes bundled on macOS are fine too.

If using a Gemfile in your project, add an "Execute shell" step as your first build step and call bundle update.


You'll find the following Jenkins plugins to be useful:

(note: We do not recommend installing the Xcode plugin)

Build Step

Add an "Execute shell" build step using your appropriate fastlane command per the example below:

fastlane appstore

Replace appstore with the lane you want to use.

(note: if using a Gemfile, prefix that command with bundle exec)


You can use setup_jenkins action which integrates well with the Keychains and Provisioning Profiles Plugin. Selected keychain will automatically unlocked and the selected code signing identity will be used. Also all build results, like IPA files, archives, dSYMs and result bundles will be stored in the ./output folder in the job workspace. In additions setup_jenkins will create separate derived data folder for each job (in the ./derivedData).

Under the hood setup_jenkins configures other actions like: gym, scan, xcodebuild, backup_xcarchive and clear_derived_data.

commit_version_bump || git_commit

You can use commit_version_bump or git_commit action to commit changes to your repository in your fastlane setup. When you are using webhooks to trigger your build on a push this will cause an infinite loop of triggering builds.


When you are using Gitlab you will need the GitLab Plugin. Inside the job you want to configure you go to Build Triggers > Build when a change is pushed to GitLab > Enable [ci-skip]. When you include [ci-skip] in your build this commit won't trigger the build in jenkins at all.


build_number = increment_build_number
commit_version_bump(message:"[ci-skip] Version Bump to #{build_number}")
git_commit(path:"./", message:"[ci-skip] Updated CHANGELOG for Build #{build_number}")

Test Results and Screenshots

To show the deployment result right in Jenkins

  • Add post-build action
  • Publish JUnit test result report
  • Test report XMLs: fastlane/report.xml

To show the generated screenshots right in Jenkins

  • Add post-build action
  • Publish HTML reports
  • HTML directory to archive: fastlane/screenshots
  • Index page: screenshots.html

Save and run. The result should look like this:


Circle Integration

To run fastlane on Circle as your CI, first create a Gemfile in the root of your project with the following content

source ""

gem "fastlane"

and run

gem install bundler && bundle update

This will create a Gemfile.lock, that defines all Ruby dependencies. Make sure to commit both files to version control.

Next, use the following circle.yml file

    version: "7.3"
    - bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3 --without development
    - vendor/bundle
    - bundle exec fastlane test

This will automatically cache the installed gems on Circle, making your CI builds much faster!

Travis Integration

Update your .travis.yml to look like this:

language: objective-c
osx_image: xcode8.3
  - bundle install
  - fastlane beta

The above config files assume you have a Gemfile set up, if you don't have one yet, make sure to follow our Gemfile guide and run bundle update to make sure you're using the most recent fastlane release.

Replace beta with the lane you want to run for your setup. If you want to build, sign and distribute builds from Travis, you'll need to add one more action to your Fastfile, as by default, the Travis keychain is locked.

At the top of your Fastfile, add


which will setup the keychain to work well with match and gym. This action will also enable the readonly mode for match, so your CI doesn't create new certificates or provisioning profiles.

Bamboo Integration

Repository setup

In bamboo under Linked Repositories (where you configure your git repo) under Advanced Settings is an option called Exclude changesets

This dialog will allow you to enter a regular expression that if a commit matches, a build will not be triggered.

For example, if your Fastfile is configured to make a commit message in the style of

Build Version bump by fastlane to Version [0.3] Build [8]

Then you could use the following regex to ignore these commits

^.*Build Version bump by fastlane.*$

Setting repository remote

By default bamboo will do an anonymous shallow clone of the repo. This will not preserve the git remote information nor the list of tags. If you are using bamboo to create commits you may want to use a code block similar to the following:

# In prep for eventually committing a version/build bump - set the git params
sh('git config "<COMMITTER USERNAME>"')
sh('git config <COMITTER EMAIL>')

# Bamboo does an anonymous checkout so in order to update the build versions must set the git repo URL
git_remote_cmd = 'git remote set-url origin ' + ENV['bamboo_repository_git_repositoryUrl']

Speeding up build times with carthage

Carthage is a wonderful dependency manager but once you are start using a large number of frameworks, things can start to slow down, especially if your CI server has to run carthage EVERY time you check in a small line of code.

One way to make build times faster is to break your work up into two separate build plans (this can get even more funky if you start having multiple branches)

The general idea is to make a build plan: Project - Artifacts that builds the Carthage directory and stores it as a shared artifact. Then you create a second build plan Project - Fastlane that pulls down the Carthage directory and runs fastlane.

Artifact Plan

Use a simple setup to create this build plan. First off you want to make sure this plan is manually triggered only - because you only need to run it whenever the Cartfile changes as opposed to after ever single commit. It could also be on a nightly build perhaps if you desire.

Stages / Jobs / Tasks

This plan consists of 1 Job, 1 Stage and 2 Tasks

  • Task 1: Source Code Checkout
  • Task 2: Script (carthage update)

Artifact definitions

Create a shared artifact with the following info:

  • Name: CarthageFolder
  • Location: (leave blank)
  • Copy Pattern: Carthage/Build/**

Optional: You may want to automatically make the fastlane plan trigger whenever this plan is built

fastlane plan

When configuring fastlane to run in this setup you need to make sure that you are not calling either:

reset_git_repo(force: true)



as these calls will either fail the build or delete the Carthage directory. Additionally you want to remove any carthage tasks from inside your Fastfile as carthage is now happening externally to the build.

Build plan setup

What this build plan does is it checks out the source code, then it downloads the entire Carthage/Build/ directory into your local project - which is exactly what would be created from carthage bootstrap and then it runs fastlane

  • Task 1: Source Code Checkout
  • Task 2: Artifact Download
  • Task 3: fastlane

GitLab CI Integration

Use GitLab CI Runner running on a macOS machine to build using fastlane.

Repository setup

First create a Gemfile in the root of your project with the following content:

source ""

gem "fastlane"

Add a .gitlab-ci.yml file to trigger fastlane.

  - unit_tests
  - test_flight

  LC_ALL: "en_US.UTF-8"
  LANG: "en_US.UTF-8"

  - gem install bundler
  - bundle install

  dependencies: []
  stage: unit_tests
      - fastlane/screenshots
      - fastlane/logs
    - fastlane tests
    - ios

  dependencies: []
  stage: test_flight
      - fastlane/screenshots
      - fastlane/logs
    - fastlane beta
    - ios
     - /^release-.*$/
     - master

See the `.gitlab-ci.yml documentation for more information on how this file works.

Setting up the lanes

You should have a lane - in this example called beta - which should do the usual, match, gym, pilot, to distribute an updated Test Flight version, and one lane tests which calls scan to run UI Tests.

Auto-incremented build number.

To get an auto-incremented build number you can use something like the following lane:

lane :increment_build_number do
  increment_build_number(build_number: ENV['CI_BUILD_ID'])

Then the GitLab CI build ID (which iterates on each build) will be used.

Visual Studio Team Services

Microsoft Visual Studio Team Services (VSTS) and Team Foundation Server (TFS) use fastlane in their Apple App Store extension.

Getting Started

Once you have created or retrieved credentials for your App Store account, then perform the following steps to automate releasing updates from a VSTS build or release definition: 1. Install the App Store extension from the VSTS Marketplace 1. Go to your VSTS or TFS project, click on the Build tab, and create a new build definition (the "+" icon) that is hooked up to your project's appropriate source repo 1. Click Add build step... and select the neccessary tasks to generate your release assets (e.g. Gulp, Cordova Build) 1. Click Add build step... and select App Store Release from the Deploy category 1. Configure the App Store Release task with the desired authentication method, the generated IPA file path, and the desired release track.

Now when you build, your app will automatically be published to iTunes Connect!

Configuring fastlane versions

The extension can be configured to install the latest version of fastlane or a specific version of fastlane: 1. In the Build for your project, click on the Apple App Store task (supported in both Apple App Store Release and Apple App Store Promote), go to the Advanced section of the Task, click Install fastlane 1. Optionally, select Specific Version from fastlane version, and enter a specific version of fastlane

More Information

For more documentation, see the Apple App Store in the Visual Studio Team Server marketplace.