skip to content

Fastlane

The de-facto automation layer for mobile releases: lanes written in Ruby that build, sign, screenshot, and upload to TestFlight or Google Play. Interviews cover how you get a reproducible signed build out of CI with no human sitting at a Mac.

on this pageshow

explore

questions

30

In fastlane, which action uploads an iOS build to TestFlight for beta testers?

level: juniorimportance: must knowfreq 68%

answer

  1. one core action, Apple only
  2. the binary comes from the build step
  3. the famous name is only an alias
  4. verb_noun form of pilot

basics

~20 s

The canonical action is upload_to_testflight, better known by its alias pilot. It takes a finished iOS binary, an App Store Connect credential and an optional changelog, and hands the build to Apple's beta service. Android has no core equivalent.

solid answer

~40 s

`upload_to_testflight` is the canonical action; `pilot` and `testflight` are aliases for the same thing. For the bookbinding order app you point it at the Apple binary — `ipa` for an iOS app, `pkg` for a macOS package — and it defaults to the path `build_app` (`gym`) left in the lane context, so a build-then-upload lane usually passes no path at all. It authenticates with an App Store Connect API key (`api_key` / `api_key_path`) or an Apple ID `username`. `changelog` carries the tester-facing note for that build, and `app_identifier` disambiguates when a repository builds several bundles. There is no core Android counterpart: Firebase App Distribution ships as a third-party plugin, and the Google Play route is `upload_to_play_store` (`supply`).

code

ruby · 10 lines
ruby
build_app(
  scheme: "BookbindingOrders",
  export_method: "app-store"
)

upload_to_testflight(
  api_key_path: "fastlane/asc_api_key.json",
  app_identifier: "com.bindery.bookbindingorders",
  changelog: "Order intake now accepts partial binding batches."
)

go deeper

for a junior

Be ready to name the action and its alias in one breath — upload_to_testflight, also called pilot — and to say plainly that it is an Apple-only upload of an already-built binary.

for a middle

Explain where the binary comes from: build_app leaves its archive path in the lane context and the upload action reads it. Name the options that identify the app and carry the changelog.

for a senior

Show how the lane behaves unattended: an App Store Connect API key rather than an interactive Apple ID, an explicit app identifier in a multi-bundle repo, and a clear failure when the binary or credential is missing.

for a principal

Own the policy question — one owned beta lane per platform versus every team hand-rolling an upload script — and decide who may change the tester-facing changelog contract.

## The action and its aliases fastlane runs **actions** from a Fastfile, and most of the famous fastlane names are aliases for a canonical `verb_noun` action. The iOS beta upload is one of them: the canonical action is **`upload_to_testflight`**, and `pilot` and `testflight` are aliases that resolve to it. Both spellings work in a Fastfile, but the canonical name is the one worth learning — it is how the action's own option list is filed, and it is what makes the family legible next to `build_app` (`gym`), `sync_code_signing` (`match`), `upload_to_app_store` (`deliver`) and `upload_to_play_store` (`supply`). Someone who only ever says *pilot* has learned a nickname, and will go looking for a `pilot` entry in the reference that is really just a pointer. The action does one job: it hands a **finished Apple binary** to Apple's beta service. It does not compile, it does not sign, and it does not decide who the testers are. ## What the upload step needs For the bookbinding order app — an iOS app a bindery uses to take and track custom binding orders — a beta upload needs four things: - **A binary.** `ipa` for an iOS app, `pkg` for a macOS package. One or the other, never both. - **A credential.** An App Store Connect API key through `api_key` or `api_key_path`, or an Apple ID through `username`. The API key is the form that works unattended on CI. - **An app identity.** `app_identifier` when the repository builds more than one bundle, and `app_platform` when the same identifier ships for more than one Apple platform. - **Optional tester-facing text.** `changelog` carries the note attached to that specific build; `localized_build_info` carries per-language variants of the build's text. Everything else in the option set — and it is a large set — governs *what happens after the bytes arrive*: whether to wait for Apple's processing, whether to distribute, which groups receive the build. ## Where the binary comes from The most common beginner move is to pass `ipa:` by hand. In a lane that builds and then uploads, you usually should not. fastlane actions communicate through a shared **lane context**: `build_app` (`gym`) writes the path of the archive it produced into `Actions.lane_context[SharedValues::IPA_OUTPUT_PATH]`, and `upload_to_testflight` uses that value as the default for `ipa`. A build-then-upload lane for the bookbinding order app therefore calls `build_app` and then the upload action with no path at all, and the two stay in step even when the output directory, the scheme or the configuration changes. Pass `ipa` explicitly when the binary did **not** come from a `build_app` call in the same run — a CI job that downloads an artifact produced in an earlier stage, a binary built by another tool, or a run that produced two products and you need to be precise about which one goes up. ## The platform split This action is **Apple-only**, and that asymmetry is the fact most often missed: | | Apple (iOS, macOS, tvOS) | Android | |---|---|---| | Core beta upload action | `upload_to_testflight` (`pilot`) | none | | Artifact it accepts | `.ipa` or `.pkg` | not accepted by this action | | Credential | App Store Connect API key, or Apple ID `username` | Google service-account JSON key | | Non-store beta route | third-party Firebase App Distribution plugin | third-party Firebase App Distribution plugin | | Core store route | `upload_to_app_store` (`deliver`) | `upload_to_play_store` (`supply`) | There is no Android branch hiding inside `upload_to_testflight`, and there is no core Android equivalent of it. **Firebase App Distribution is a third-party plugin** (`fastlane-plugin-firebase_app_distribution`) that has to be added to the project before its action exists at all. The other Android route is the Play upload lane `upload_to_play_store` (`supply`) aimed at a non-production track — a store lane rather than a beta lane, with a service-account key rather than an Apple credential. ## What the action does not do Three boundaries keep the answer honest: 1. It does not **build**. If the archive is missing, the defect is in the build step, not in the upload. 2. It does not **sign**. Signing assets come from `sync_code_signing` (`match`) and are consumed when the archive is exported. 3. It does not **create testers**. Options such as `groups` and `distribute_external` name an audience that already exists; who belongs to that audience is administered in Apple's console, not by the lane. Knowing exactly where the lane stops is what separates someone who has followed a fastlane tutorial from someone who owns the pipeline.

  • If a lane builds and uploads in the same run, must you pass `ipa` to the upload action?
    No. `build_app` (`gym`) publishes the archive path into the lane context as `SharedValues::IPA_OUTPUT_PATH`, and `upload_to_testflight` defaults `ipa` to it. Pass the path explicitly only when the binary came from somewhere else — a downloaded CI artifact, another tool, or a run that produced more than one product and you need to name which one goes up.
  • What uploads an Android beta build, given that this action is Apple-only?
    Not a core action. Firebase App Distribution is a third-party fastlane plugin (`fastlane-plugin-firebase_app_distribution`) that must be added to the project before its action exists. The core Android path is instead the Play upload lane `upload_to_play_store` (`supply`) pointed at a non-production track, authenticated with a Google service-account JSON key rather than an Apple credential.

saying these in an interview costs you the question

  • Thinking pilot is a different tool from upload_to_testflight
  • Assuming the same action can upload an Android artifact
  • Believing Firebase App Distribution is a built-in fastlane action
  • Expecting the upload action to build or sign the app
  • Passing an Apple ID password where an API key is expected
open as a page

In a fastlane Fastfile, what does a lane declare, and how does a CI step invoke one?

level: juniorimportance: must knowfreq 78%

basics

~20 s

A lane is a named, ordered sequence of fastlane actions declared in the Fastfile. CI invokes one by name, such as fastlane ios beta for a lane inside a platform ios block, and the lane's exit status decides the step.

open as a page

What does fastlane's build_app action (gym) produce for an iOS app?

level: juniorimportance: must knowfreq 80%

basics

~10 s

fastlane's build_app action, whose alias is gym, wraps Apple's xcodebuild for iOS: it archives the scheme you name, then exports a signed .ipa plus the archive's dSYM debug-symbol bundles into an output directory.

open as a page

In fastlane, which action captures store screenshots on iOS, and which one on Android?

level: juniorimportance: must knowfreq 72%

basics

~20 s

fastlane captures iOS store screenshots with capture_ios_screenshots, better known as snapshot, which drives an XCUITest on simulators; Android uses capture_android_screenshots, known as screengrab, which drives a separate instrumentation test APK on a device or emulator.

open as a page

How does a fastlane upload lane authenticate to App Store Connect and to Google Play without a human login?

level: juniorimportance: must knowfreq 78%

basics

~20 s

Apple and Google use different credentials. upload_to_app_store takes an App Store Connect API key through api_key or api_key_path; upload_to_play_store takes a Google service-account JSON key through json_key or json_key_data. There is no shared credential model.

open as a page

In a fastlane Fastfile, when do before_all, before_each, after_all and error each run?

level: middleimportance: must knowfreq 58%

basics

~20 s

before_all runs once before the first lane of a run and before_each before every lane in it. after_each and after_all run only on success, after_all once at the end. error is the single hook that fires when a lane or action raises.

open as a page

In fastlane's build_app, what does export_method decide about the resulting iOS .ipa?

level: middleimportance: must knowfreq 74%

basics

~10 s

export_method tells fastlane's build_app which Apple distribution channel the export is signed for - app-store, ad-hoc, enterprise or development - and that choice decides which provisioning profile and entitlements are baked into the .ipa.

open as a page

In fastlane, how do you choose between upload_to_testflight for iOS and the Firebase App Distribution plugin?

level: seniorimportance: must knowfreq 55%

basics

~20 s

upload_to_testflight is a core, Apple-only action whose builds wait on Apple's processing before testers can install them. Firebase App Distribution is a third-party plugin that reaches both platforms faster but is a less official channel. Most teams run both.

open as a page

Your iOS build_app export picks the wrong provisioning profile — how do you pin it?

level: seniorimportance: must knowfreq 56%

basics

~20 s

Stop the guessing and state the mapping: set skip_profile_detection in fastlane's build_app, pin the Apple team with export_team_id, and pass export_options carrying an explicit bundle-identifier-to-profile map, ideally the one sync_code_signing published into the lane context.

open as a page

What keychain setup does match need on a macOS CI runner to install iOS signing certificates?

level: seniorimportance: must knowfreq 64%

basics

~20 s

match imports the private key into a macOS keychain, so a CI runner needs a dedicated keychain created, unlocked and kept in the search list for the whole build, named to sync_code_signing through keychain_name and keychain_password.

open as a page

How does a fastlane lane receive parameters, and how do you pass them from the command line?

level: juniorimportance: should knowfreq 64%

basics

~20 s

A lane declares a block parameter, conventionally options, which is a hash of the values the caller passed. Command-line callers append key:value pairs after the lane name; a calling lane passes a Ruby hash. Command-line values arrive as strings.

open as a page

In a fastlane Fastfile, what does private_lane change about a lane, and when is it the right choice?

level: juniorimportance: should knowfreq 47%

basics

~20 s

private_lane declares a lane that is not a command-line entry point; only other lanes in the same Fastfile can call it. Use it for shared helper steps so the file's invocable entry points stay few and obvious.

open as a page

What problem does fastlane's match (sync_code_signing) solve for iOS code signing?

level: juniorimportance: should knowfreq 66%

basics

~20 s

match, whose canonical action name is sync_code_signing, keeps one team's Apple certificates and provisioning profiles in an encrypted shared repository, so every developer machine and CI runner signs the iOS app with the same identity instead of enrolling its own.

open as a page

In fastlane, which action uploads an iOS build to App Store Connect and which uploads an Android build to Google Play?

level: juniorimportance: should knowfreq 70%

basics

~10 s

fastlane's upload_to_app_store, nicknamed deliver, sends an iOS build and its listing metadata to App Store Connect. upload_to_play_store, nicknamed supply, sends an Android APK or AAB to Google Play. Both spellings work in a Fastfile.

open as a page

How does a fastlane beta lane get changelog text to iOS TestFlight testers versus Android testers?

level: middleimportance: should knowfreq 41%

basics

~20 s

On iOS the changelog is an inline string: upload_to_testflight takes a changelog option, plus localized_build_info for per-language text. Android has no core beta action at all, so release notes ride on the third-party Firebase App Distribution plugin instead.

open as a page

Why should a CI runner call match with readonly: true for an iOS build?

level: middleimportance: should knowfreq 58%

basics

~20 s

readonly true makes sync_code_signing only fetch and install existing Apple certificates and profiles, never creating, renewing or revoking any. A CI runner then cannot mint a new certificate, exhaust the team's certificate slots, or write to the shared signing repository.

open as a page

In fastlane, what does frame_screenshots (frameit) do after iOS or Android screenshots are captured?

level: middleimportance: should knowfreq 41%

basics

~20 s

frame_screenshots, aliased frameit, is pure image post-processing: it reads the PNGs already produced by capture_ios_screenshots on iOS or capture_android_screenshots on Android and writes framed copies, each screenshot composited inside a device bezel with an optional background and title.

open as a page

In fastlane, how do you choose screenshot locales on iOS versus Android?

level: middleimportance: should knowfreq 56%

basics

~20 s

On iOS, capture_ios_screenshots takes a languages list and can localize the simulator itself; on Android, capture_android_screenshots takes a locales list plus ending_locale, the locale the shared device is restored to once the capture run finishes.

open as a page

Your fastlane iOS lane exits before the TestFlight build is testable; which upload_to_testflight options control that wait?

level: seniorimportance: should knowfreq 47%

basics

~10 s

Uploading an iOS build to TestFlight is not the same as the build being testable: Apple processes it first. Four upload_to_testflight options govern that wait — skip_waiting_for_build_processing, wait_for_uploaded_build, wait_processing_interval and wait_processing_timeout_duration.

open as a page

Your fastlane release lane fails halfway on CI and leaves the runner dirty — how do you restructure the Fastfile?

level: seniorimportance: should knowfreq 41%

basics

~20 s

Move cleanup out of after_all, which is skipped on failure, into the error hook. Split the long lane into re-runnable lanes that take the artifact path as a parameter, and assert the run's prerequisites in before_all so failures happen early and cheaply.

open as a page

On CI, which build_app options decide where an iOS build's artifacts, derived data and logs land?

level: seniorimportance: should knowfreq 48%

basics

~10 s

In fastlane's build_app, derived_data_path places Xcode's intermediates, build_path and archive_path place the .xcarchive, output_directory and output_name place the exported .ipa, buildlog_path saves the raw xcodebuild log, and result_bundle writes the .xcresult.

open as a page

A revoked Apple distribution certificate breaks every iOS build; how do you recover the match repository?

level: seniorimportance: should knowfreq 47%

basics

~20 s

Regenerate from a machine with write access, never from CI. Run sync_code_signing without readonly and with force to recreate the profiles, or nuke the unusable material first, then let developers and readonly runners sync the new encrypted assets down.

open as a page

Your fastlane screenshot lane produces dirty, run-to-run varying store shots — how do you make capture clean and repeatable on iOS and Android?

level: seniorimportance: should knowfreq 47%

basics

~20 s

Control three things separately: the machine, the app data and the artifacts. On iOS use erase_simulator, reinstall_app and override_status_bar; on Android use reinstall_app, stable filenames and ending_locale; and on both use clear_previous_screenshots plus launch_arguments to seed fixed data.

open as a page

In fastlane, how do captured screenshots and localized metadata reach the upload actions on iOS and Android?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Through directories on disk, not return values. Capture writes one folder per locale under output_directory; on Apple, upload_to_app_store reads a separate screenshots_path and metadata_path, while on Google Play upload_to_play_store reads a single metadata_path tree that already contains the images.

open as a page

In fastlane, which upload_to_app_store and upload_to_play_store options release a llama-trekking booking app on iOS and Android with nobody at a console?

level: seniorimportance: should knowfreq 54%

basics

~20 s

On Apple's side upload_to_app_store needs submit_for_review, force to skip the confirmation prompt, and the submission and review information options; automatic_release, auto_release_date and phased_release control the release itself. On Google's side upload_to_play_store needs track, release_status and rollout.

open as a page

When should an iOS build reach for build_app's xcargs instead of a first-class option?

level: principalimportance: should knowfreq 38%

basics

~20 s

Only when no named option covers it. In fastlane's build_app, xcargs passes raw arguments to Apple's xcodebuild, so prefer validated options such as configuration or sdk, keep project-level settings in an xcconfig, and use export_xcargs for export-only flags.

open as a page

Which storage backends can match use for a team's encrypted Apple signing assets?

level: middleimportance: nice to knowfreq 42%

basics

~10 s

sync_code_signing supports exactly four storage backends, chosen with storage_mode: git, google_cloud, s3 and gitlab_secure_files. match encrypts the Apple certificates and profiles with OpenSSL before writing, so whichever backend you pick only ever holds ciphertext.

open as a page

In fastlane, where do upload_to_app_store and upload_to_play_store read iOS and Android release notes from?

level: middleimportance: nice to knowfreq 42%

basics

~20 s

Both read a metadata folder set by metadata_path, but the layouts differ. upload_to_app_store reads a per-locale release_notes entry and also accepts the text inline as an option; upload_to_play_store reads per-locale changelog files named after the Android version code.

open as a page

In fastlane, which upload_to_app_store and upload_to_play_store options name an iOS or Android release version?

level: middleimportance: nice to knowfreq 46%

basics

~20 s

On Apple's side upload_to_app_store uses app_version and build_number to choose the App Store Connect version and the build attached to it. On Google's side upload_to_play_store uses version_name and the integer version_code that Play orders releases by.

open as a page

In fastlane, how do you distribute an iOS build already in TestFlight without uploading it again?

level: seniorimportance: nice to knowfreq 32%

basics

~20 s

Pass distribute_only: true to upload_to_testflight. The action then skips the upload entirely and only runs distribution for a build already in TestFlight, identified by app_identifier with app_version and build_number, so no iOS binary is needed.

open as a page