fastlane Tutorial: Getting Started

In this fastlane tutorial, you’ll learn how to provision, screenshot, build and upload an app to the App Store using fastlane. By Lyndsey Scott.

4.8 (23) ·

Download materials
Save for later
Update note: Lyndsey Scott updated this tutorial for Xcode 10.1, Swift 4.2, Ruby 2.5.1 and fastlane 2.112.0. Satraj Bambra wrote the original.

It’s that wonderful moment: You’ve poured days, weeks or maybe even months into building an app, and it’s finally ready to share with the world. All you have to do is submit it to the App Store. How hard could that be, right?

Cue mountains of grunt work: capturing tons of screenshots, adding your app to the Apple Developer and App Store Connect sites, uploading your binary and metadata and other mindless work! Argh!

Isn’t there a better way? If only you could run a single command that took all your screenshots on all your supported devices, in every supported language automagically. If only there were a single command to upload those screenshots, add your app to Apple’s developer sites and submit it all. Think of all the time you’d save!

Well, you’re in luck. :] Thanks to creator Felix Krause and lead maintainer Josh Holtz, there’s a tool to do all this and more! It’s called fastlane! In this tutorial, you’ll learn how to use fastlane to deploy an app to the App Store. It’s sure to become your new best friend. Even Google’s buddied up with fastlane by acquiring it in 2017.

fastlane tutorial

If sticks were screenshots, this dog would be nearly as helpful as fastlane.

Note: This tutorial assumes that you have a paid Apple Developer account, as well as a basic knowledge of the command line, Xcode and the app submission process. If you don’t have an account, this tutorial will help you.

Getting Started

First, download the materials for this tutorial at the top or bottom of this page using the Download Materials button, then save them to a convenient location.

This tutorial’s sample app, mZone Poker, is a poker calculator for No Limit Texas Hold ‘Em tournaments. It displays a recommended action based on your chip count and the current big blind level.

Open the mZone project in Xcode to build, run and check it out.

mZone starter

Setting Up fastlane

The tool fastlane is a collection of Ruby scripts, so you must have the correct version of Ruby installed. Chances are that your OS comes with Ruby 2.0 by default, but you can confirm whether this is the case by opening Terminal and entering:

ruby -v

If it’s not installed, the easiest way to do so is via Homebrew a package manager for macOS.

Install Homebrew by entering this Terminal command:

/usr/bin/ruby -e \
  "$(curl -fsSL"

Then, install Ruby using:

brew update && brew install ruby

Run brew link --overwrite ruby and/or open a new Terminal session if Homebrew instructs you to do so.

You’ll also need Xcode Command Line Tools (CLT). To ensure that they’re installed, enter into Terminal:

xcode-select --install

If Xcode CLT are already installed, you will get this error: xcode-select: error: command line tools are already installed, use "Software Update" to install updates. If not, continue the installation when prompted.

Now you’re ready to install fastlane! Enter the following command to do so:

sudo gem install -n /usr/local/bin fastlane --verbose

If you prefer to use Homebrew enter the following command:

brew cask install fastlane
Note: With El Capitan, OS X introduced System Integrity Protection, also known as Rootless, which prevents users from having root access. /usr/local/bin is still writable, which is why you’re installing fastlane there.

After entering your system password, you will see a bunch of activity in Terminal indicating that the installation is in progress. This could take a few minutes, so grab some coffee, walk your dog or brush up on your zombie-fighting tactics. :]

Once installation completes, you’re ready to set up fastlane in your project. But before you do, here’s a high-level look at the fastlane tools.

The fastlane Toolchain

To work its magic, fastlane brings the following set of tools all under one roof:

  • produce creates new iOS apps in both App Store Connect and the Apple Developer Portal.
  • cert automatically creates and maintains iOS code-signing certificates.
  • sigh creates, renews, downloads and repairs provisioning profiles.
  • snapshot automates taking localized screenshots of your iOS app on every device.
  • frameit puts your screenshots into the right device frames.
  • gym builds and packages your iOS apps.
  • deliver uploads screenshots, metadata and your apps to the App Store.
  • pem automatically generates and renews your push notification profiles.
  • spaceship is a Ruby library able to access the Apple Developer Center and App Store Connect APIs.
  • pilot automates TestFlight deployments and manages beta testers.
  • boarding invites beta testers.
  • match syncs certificates and provisioning profiles across your team, using Git.
  • scan runs tests on your apps.

You’ll use several of these tools today. Enough with the theory for now — it’s time to put this tutorial into gear and enter the fast lane!

Adding fastlane to Your Project

Open Terminal and cd into your mZone starter project. For example, if you’ve added the mZone_Sample_Project folder to your desktop, you can enter:

cd ~/Desktop/mZone_Sample_Project/mZone

To set the mZone starter project as the working directory.

Next, enter:

fastlane init

To initialize fastlane.

Notes: If you get a “permission denied” error, prefix this command with sudo.

If at any point, fastlane tells you to update to a newer version, but running sudo gem update fastlane outputs that there is “Nothing to update,” perhaps the Ruby manager you’re using isn’t up to date. Run gem sources --add to install Ruby Gems since it’s likely to produce the most current information.

After some output, fastlane will ask: “What would you like to use fastlane for?”

output fast lane init

fastlane init output

Although fastlane “recommend[s] automating one task first,” you’ll implement multiple automated actions during this single tutorial, so input 4 to commence manual setup. Read the output and press Enter when prompted.

Back in the mZone folder, you’ll see a few new things: Gemfile, which includes the fastlane gem as a project dependency and a fastlane folder containing:

  • Appfile: stores the app identifier, your Apple ID and any other identifying information that fastlane needs to set up your app.
  • Fastfile: manages the lanes you’ll create to invoke fastlane actions.

generated files

Open Fastfile in a text editor of your choice, disable smart quotes if your text editor supports them, then replace the contents of the file with:


platform :ios do
# 1
  desc "Create app on Apple Developer and App Store Connect sites"
# 2
  lane :create_app do
# 3
​    produce

If you’ve never seen Ruby before, this may look like gibberish to you. Here’s what this code does:

  1. Provides a description for the lane. (A lane is a workflow of sequential tasks).
  2. Names this lane create_app.
  3. Uses produce to add the app to both the Developer Portal and App Store Connect.

Woohoo! You have now created your very first lane.


Save Fastfile, then open Appfile. Remove the pound (#) sign to uncomment the line starting with apple_id, then replace [[APPLE_ID]] with your actual Apple ID username. By setting this information now, fastlane won’t have to repeatedly prompt you for it later on.

Note: If your App Store Connect and Apple Developer Portal usernames are different, replace the apple_id line with:

Then replace each username placeholder with its respective username.

Save Appfile before closing.

Creating Your App

Open Terminal inside your project folder and enter:

fastlane create_app

This runs the create_app lane you just created.

You should see something like this:

output create app

At the top of that output, fastlane suggests that you precede your fastlane command with “bundle exec” in order to launch fastlane faster in the context of the gem bundle. Going forward, you can do so.

Enter your App Store Connect password if prompted. If your Developer Portal has multiple teams, enter the number corresponding to the team you’d like to use for your mZone Poker app.

Eventually, produce will ask you to enter your bundle ID. Time to create one!

The bundle identifier must be different from every other bundle identifier anyone’s ever used in App Store Connect. Try to enter a unique bundle identifier by using the following format:

com.mZone-Poker.[Insert your email address minus “@” and “.”]

output create bundle id

If the bundle identifier’s already taken, edit it and try again until you’ve submitted a unique ID.

Then, when you’re prompted to submit an app name, it too will have to be unique. Try using the following format:

mZone Poker [Insert your email address minus “@” and “.”]

App names can’t be longer than 30 characters, though, so truncate as necessary.

If your App Store Connect account has multiple teams, enter the number corresponding to the team you’d like to use.

If you receive any errors stating that there’s a problem with your Apple Developer account (for example, if you need to accept a new program agreement), correct the issue then run produce again.

If the app name is unavailable, the process will end with an error. Run produce again, re-enter your Apple ID and the same Bundle ID you just created, then either flex your creative muscles to create a unique ID or return to the top of this paragraph and repeat. Frustrating we know, but we’re confident you’ll break the infinite loop!

Log in to Apple Developer Center and App Store Connect. Voilà! Your app has already been added to both. How cool is that? :]

developer portal

Apple Developer (above), App Store Connect (below)

Reopen Appfile, uncomment the line starting with app_identifier, then replace [[APP_IDENTIFIER]] with the bundle ID you just created.

If you had to choose a team earlier, add the team’s name so you won’t have to enter it again when running your lanes. To specify your Developer Portal/App Store Connect team name, add:

team_name ("[[TEAM_NAME]]")

Replace [[TEAM_NAME]] with your team’s name.

Generating the Deliverfile

Back in Terminal, enter:

bundle exec fastlane deliver

When fastlane asks; “Do you want to setup deliver?” Enter y in response.

Next fastlane will ask, “Would you like to use Swift instead of Ruby?” Although, as an iOS developer, you’re probably more comfortable working in Swift, as of the writing of this tutorial, fastlane.swift is still in beta. So enter n to use Ruby in your fastlane files.

output deliver

Once deliver successfully completes, navigate back to mZone/fastlane in your Finder and you’ll see some new things:

  • The metadata directory, which will hold the majority of the app’s metadata.
  • Deliverfile, which will hold a few remaining pieces of metadata.
  • The screenshots directory, which will contain the app screenshots.

metadata directory structure

In the metadata directory, you’ll notice a bunch of text files named after common App Store items like the description, keywords, categories, etc. fastlane will use these files to submit your app’s metadata information to App Store Connect.

Open en-US/description.txt and add:

mZone is a simple poker calculator for No Limit Texas Hold 'Em tournaments that displays a recommended course of action based on your chip count and the current big blind level.

To keywords.txt add:

Poker, Cards, Gambling

Confirm that name.txt already contains the name of your app, then add to both privacy_url.txt and support_url.txt.

While this app supports both French and English, only the en-US folder exists. To fix this, make a copy of the en-US folder in its same directory and call it fr-FR. In the interest of keeping this fastlane tutorial short, you won’t have to translate the metadata into French… this time. ;]

Next, in the metadata folder:

  • Add Copyright (c) 2019 Razeware LLC to copyright.txt.
  • Add Games to primary_category.txt.
  • Add Card to primary_first_sub_category.txt.
  • Add Casino to primary_second_sub_category.txt.

Then, in the same folder, use your favorite text/code editor to create a JSON file named app_store_rating_config.json containing:

  "HORROR": 0,
  "GAMBLING": 2,

This rating configuration indicates that the app has “frequent/intense” simulated gambling (i.e., value = 2) and none of the other listed content. This file gives Apple the information it needs to assign an appropriate age rating.

And, lastly, in the review_information folder, add your email address to email_address.txt, your first name to first_name.txt, your last name to last_name.txt and your phone number to phone_number.txt. Preface the phone number with ‘+’ followed by the country code, for example; +44 844 209 0611.

Congratulations! You’ve added all the metadata required for submission.

Note: You can find a full list of metadata options and Deliverfile settings here.

Automating Screenshots

Taking screenshots can be tedious. The more devices and languages your app supports, the more hours you’ll burn. Painful!

mZone Poker supports two languages and two iPhone screen aspect ratios. If you had to take five screenshots per device for each language and screen aspect ratio, that would be 20 screenshots! With fastlane, however, you can do all this by running a single command.

Set up the project for snapshot by entering in Terminal:

fastlane snapshot init

A Snapfile file will now appear in your fastlane folder. Open it and replace the contents of the file with:

# 1 - A list of devices you want to take the screenshots from
  "iPhone 8 Plus",
  "iPhone SE"

# 2 - A list of supported languages


# 3 - The name of the scheme which contains the UI Tests

scheme("mZone Poker UITests")

# 4 - Where should the resulting screenshots be stored?

output_directory "./fastlane/screenshots"

# 5 - Clears previous screenshots


Here, you specify:

  1. The devices from which you want fastlane to capture your screenshots.
  2. The localized languages you want to capture.
  3. The name of the Xcode scheme you’ll soon create to run screenshot automation.
  4. The screenshot output directory.
  5. That fastlane should clear any screenshots in the output directory before capturing new ones.

Save the file before closing.

Return to Terminal and note the instructions that appeared after running fastlane snapshot init:

output snapshot init

That’s what you’ll do next.

Creating a Test Target

Open mZone Poker.xcodeproj in Xcode then navigate to File ▸ New ▸ Target. Within the iOS tab’s Test section, select iOS UI Testing Bundle then click Next.

add uitest target

In the Product Name field, enter mZone Poker UITests then click Finish.

add uitest target

An mZone Poker UITests folder should now appear in Xcode’s left-hand navigator menu.

Go to the target’s General page. Below the mZone Poker target, you’ll now see mZone Poker UITests. Select mZone Poker UITests and if you see an error stating that Signing for “mZone Poker UITests” requires a development team, select a team.

target settings

Return to the fastlane directory then drag SnapshotHelper.swift below the mZone Poker UITests folder in Xcode’s project navigator. When the Choose options for adding these files window appears, select:

  • Copy items if needed.
  • Create groups.
  • mZone Poker UITests.

Deselect the mZone Poker target before clicking Finish.

add snapshot helper file

Next, open mZone_Poker_UITests.swift in mZone Poker UITests. Remove both setUp() and tearDown(), then replace the contents of testExample() with:

// 1
let app = XCUIApplication()
// 2
let chipCountTextField = app.textFields["chip count"]
// 3
let bigBlindTextField = app.textFields["big blind"]
// 4
// 5
app.buttons["what should i do"].tap()

Here’s what this code does:

  1. Sets up the test to take snapshots and launches the app.
  2. Taps the Chip Count text field (the accessibility identifier of which was pre-set to “chip count” in the Storyboard) and enters 10 into that field.
  3. Taps the Big Blind text field and enters 100.
  4. Takes a snapshot to show how the app looks with user entries.
  5. Taps the What Should I Do? button then takes another screenshot to capture the resulting alert.

Next, to create the mZone Poker UITests scheme, click the button immediately to the right of the run and stop buttons and select Manage Schemes…. Select Show next to mZone Poker UITests and Shared next to both targets to grant fastlane access. Then, click the mZone Poker UITests row and Edit….

Note: If the scheme doesn’t appear, click the + and select mZone Poker UITests from the Target drop-down.

manage schemes

Click Build in the scheme editor’s left-hand menu. Then, next to the mZone Poker UITests target, select the Test and Run options before clicking Close to save your changes.

edit scheme

Leave Xcode, open Fastfile and, below the create_app lane, add:

  desc "Take screenshots"
  lane :screenshot do

This screenshot lane uses snapshot to take screenshots as per Snapfile’s settings.

Save Fastfile, return to Terminal and enter:

bundle exec fastlane screenshot

Now, watch… the screenshots are captured without you having to do anything else! Bask in the joy of skipping grunt work. :]

An HTML preview of the screenshots should automatically open once snapshot completes.

generated screenshots

Note: snapshot needs to access the simulators listed in Snapfile. If you’re missing one or more devices from that list, add them in Xcode by going to Window ▸ Devices. Then, click + to add new simulators.

If you see warnings about ambiguous simulator names, you may need to either delete duplicate simulators or change simulator names to match those in the Snapfile.

All your device screenshots in both English and French with just one command — it doesn’t get better than that!

Creating the IPA File

Building and uploading the app can also be a time-consuming process. But guess what — fastlane can do this with its gym tool!

Note: Be sure you’ve set your bundle identifier and signing identity in the mZone Poker target in Xcode.

In Terminal, run:

fastlane gym init

To create Gymfile.

Open Gymfile and replace its contents with:

# 1
scheme("mZone Poker")
# 2
# 3
# 4

This code does the following:

  1. Specifies mZone Poker’s scheme.
  2. Specifies where fastlane should store the .ipa app binary file.
  3. Excludes bitcode from the build. Bitcode allows Apple to optimize your app, but exclude it for now to speed up the build.
  4. Excludes symbols from the build. Including symbols allows Apple to access the app’s debug information, but exclude it for now to speed up the build.
  5. Allows Xcode to use automatic provisioning.

Open Fastfile and add the following below the screenshot lane:

  desc "Create ipa"
  lane :build do
    # 1
    # 2
    # 3

This build lane:

  1. Enables automatic provisioning in Xcode.
  2. Increases the build number by 1 (so each build number is unique per App Store Connect’s upload requirement).
  3. Creates a signed .ipa file.

Save Fastfile, then run build in Terminal:

bundle exec fastlane build

If you’re prompted to enter your keychain password in order for fastlane to access your certificates, do so. Select Allow Always if you don’t want to repeatedly grant the same permission. Once build successfully completes, the signed .ipa should appear in fastlane/builds.

build directory

Uploading to App Store Connect

To upload the screenshots, metadata and .ipa file to App Store Connect, you’ll use deliver.

First, replace Deliverfile‘s contents with:

# 1
# 2
    export_compliance_encryption_updated: false,
    export_compliance_uses_encryption: false,
    content_rights_contains_third_party_content: false,
    add_id_info_uses_idfa: false
# 3
# 4
ipa("./fastlane/builds/mZone Poker.ipa”)
# 5
# 6

Here you:

  1. Set price tier to 0, indicating it’s a free app.
  2. Answer the questions Apple would present to you upon manually submitting for review.
  3. Provide the app rating configuration location.
  4. Provide the .ipa file location.
  5. Set submit_for_review to true to automatically submit the app for review.
  6. Set automatic_release to false so you’ll have to release the app manually after it’s accepted by app review.

Open Fastfile. After the build lane, add:

  desc "Upload to App Store"
  lane :upload do

Then, for fastlane to create a preview of the metadata, open Terminal and enter:

bundle exec fastlane upload

If everything looks good, type y into Terminal to approve.

Once the lane completes, log in to App Store Connect. The screenshots, metadata and build should be there, waiting for review.

App Store Connect

Putting It All Together

You now have separate lanes for creating your app, taking screenshots, building and uploading. While you could call them one-by-one, you don’t want to, right?

Oh, no — you want one command that does everything.

Open Fastfile. After the upload lane, add:

  desc “Create app, take screenshots, build and upload to App Store"
  lane :do_everything do

Fittingly, do_everything takes care of everything. :]

Furthermore, to make the lane completely hands-free, open Deliverfile and, at the bottom, add:


This causes fastlane to skip screenshot and metadata approval.

Now, to let fastlane do all the heavy lifting, run:

bundle exec fastlane do_everything

Supporting Multiple Targets

See that Multiple_Targets folder in mZone_Sample_Project? Open Multiple_Targets/mZone-2/mZone Poker.xcodeproj in Xcode. This project should look a lot like the first except with two new targets: mZone Poker Pro and mZone Poker Pro UITest.

To switch between running mZone Poker and mZone Poker Pro, click the button immediately to the right of the Run and Stop buttons, then select the scheme of whichever app you wish to run.

switch schemes

Select the scheme of the app you’d like to run.

Build and run mZone Poker Pro. It’s almost identical to mZone Poker, but returns more detailed suggestions.

mZone Pro

                            mZone Poker                                               mZone Poker Pro

On the General page, set mZone Poker’s bundle identifier to the one you created earlier.

Then, set a tentative new bundle ID for mZone Poker Pro; for example:

com.mZone-Poker-Pro.[Insert your email address minus “@”  and “.”]

Now, return to Finder. Copy and paste Gemfile and the fastlane directory from mZone into mZone-2. Then, drag mZone-2/fastlane/SnapshotHelper.swift into the new project. When the Choose options for adding these files window appears, select:

  • Copy items if needed.
  • Create groups.
  • mZone Poker UITests.
  • mZone Poker Pro UITests.

Then, click Finish.

Add snapshots helper file

Setting Up Multiple Environments

Environment (.env) files hold configuration settings that an app may access variably during its execution. For this project, you’ll create two environments — one for each app target.

Open up your favorite text editor, disable smart quotes and enter:

SCHEME = "mZone Poker"
TEST_SCHEME = "mZone Poker UITests"

This environment holds mZone Poker’s environment scheme, test scheme, bundle identifier and app name. Replace [[YOUR UNIQUE BUNDLE IDENTIFIER]] with mZone Poker’s bundle ID and [[YOUR UNIQUE APP NAME]] with the app’s unique name.

Save the file to mZone-2/fastlane as .env.mZone_Poker (with no file suffix). Since .env variables are hidden files by default, if you can’t see .env.mZone_Poker in Finder, press Shift-Command-. while in Finder to make your hidden files visible.

Similarly, create a second file containing:

SCHEME = "mZone Poker Pro"
TEST_SCHEME = "mZone Poker Pro UITests"

Replace [[YOUR UNIQUE BUNDLE IDENTIFIER]] mZone Poker Pro’s current bundle ID. Then create a tentative unique app name, ex.:

mZone Poker Pro [Insert your email address minus “@”  and “.”]

Remember, app names can’t be longer than 30 characters, so truncate as necessary.

Save the file as .env.mZone_Poker_Pro in the same directory.

Now, you’ll be able to use variables to access the current settings as you switch between schemes.

For starters, open Appfile, uncomment the app_identifier line and replace:




“ENV[‘BUNDLE_IDENTIFIER’]” tells fastlane to grab the bundle ID from whichever you set as the current environment.

In Deliverfile, replace the .ipa line with:


In Gymfile, replace the scheme line with:


In Snapfile, replace the scheme and output_directory lines with:



output_directory "./fastlane/screenshots/#{ENV['SCHEME']}"


Lastly, return to the new metadata directory. Select all of its contents and place them in a new folder named mZone Poker.

duplicate metadata

Then, duplicate that folder and name that duplicate mZone Poker Pro.

duplicate metadata

Change the contents of mZone Poker Pro/en-US/name.txt and mZone Poker Pro/fr-FR/name.txt to the new app’s name. Keep all the other metadata the same for now for simplicity’s sake.

Now, to run all the commands for the second target, you can enter:

bundle exec fastlane do_everything --env mZone_Poker_Pro

This will run do_everything using .env.mZone_Poker_Pro’s variables.

But what if you want to run all the commands for all the targets at once?

Open Fastfile. Below do_everything, add:

  def execute_for_all_envs
    # 1
    schemeList = Dir.glob(".env.*”)
    # 2
    schemeList.each do |file|
      # 3
      # 4

This method:

  1. Puts the current directory’s .env. files into an array.
  2. Loops through each .env file.
  3. Overloads ENV with the current .env file.
  4. Executes the block following execute_for_all_envs invocation.

Then, to call execute_for_all_envs from do_everything, replace the content of do_everything with:

    if ENV['SCHEME'] != nil
      execute_for_all_envs{ do_everything }

Now, if you don’t specify an environment in the command line, ENV[‘SCHEME’] == nil and thus execute_for_all_envs runs. execute_for_all_envs sets ENV to the first environment, returns to the calling block, which then re-runs do_everything.

After do_everything does everything for that environment, the loop in execute_for_all_envs continues and returns the next environment, and so on.

That’s it!

Now you can run:

bundle exec fastlane do_everything

To have fastlane do all the heavy lifting for both targets while you sit back and relax.

fastlane tutorial

Caution: It might feel weird having so much time on your hands compared to your pre-fastlane existence, but trust us, you’ll get used to it. :]

Where to Go From Here?

Check out mZone-Final and mZone-Final-2 using the Download Materials button at the top or bottom of the tutorial to see how the final projects stack up compared to yours.

fastlane also supports TestFlight submission and a ton of integrations. You can customize your lanes to provide real-time feedback on Slack, interact with Jira boards, etc. Visit the the official fastlane website to learn more.

Questions or comments? Feel free to join the forum discussion below!