skip to content

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

level: juniorimportance: must knowfreq 78%

answer

  1. one file, many named entry points
  2. desc documents, lane registers
  3. platform block prefixes the name
  4. actions run in written order
  5. exit status is the CI verdict

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.

solid answer

~40 s

A **lane** is fastlane's unit of invocation. `lane :beta do |options| ... end` in the Fastfile registers an ordered list of actions under the name `:beta`, and the `desc` line above it gives the one-line description fastlane shows when it lists the file's lanes. The actions run in the written order inside one Ruby process — for the iOS path of the orchard spray-diary app that is `sync_code_signing` (the action `match` aliases), then `build_app` (aliased `gym`), then `upload_to_testflight` (aliased `pilot`) for the upload to Apple's beta service. The first action that raises aborts the lane and the process exits non-zero. Wrapping lanes in `platform :ios do ... end` scopes them, so the lane is invoked as `fastlane ios beta`. That single command is the entire CI contract.

code

ruby · 8 lines
ruby
platform :ios do
  desc "Archive the orchard spray-diary app for Apple TestFlight"
  lane :beta do |options|
    sync_code_signing(type: "appstore")
    build_app(scheme: "SprayDiary", output_directory: "artifacts")
    upload_to_testflight
  end
end

go deeper

for a junior

Be ready to write a lane from memory: the lane keyword, a symbol name, a desc line above it, and actions in order. Then say the exact command a CI step would run to invoke it.

for a middle

Explain the mechanics: registration versus execution, why a platform block changes the invocation, how values move between actions through lane_context, and why the process exit status is what CI reads.

for a senior

Show the judgment about lane size and boundaries — which release steps deserve their own invocable lane so a failed run can be resumed, and what stays in the pipeline configuration rather than the Fastfile.

for a principal

Own the seam between pipeline and repository: a thin CI file calling one lane name keeps release logic reviewable and reproducible locally, and you should be able to argue that tradeoff against teams that push the same logic into pipeline configuration.

## The Fastfile is a registry, not a script fastlane reads one Ruby file — the **Fastfile**, kept in the repository with the app — written in fastlane's own small domain-specific language. Loading that file does not build anything; it **registers named blocks**. Only the block whose name you ask for on the command line actually executes. The lane-structure vocabulary is short and closed: `lane`, `private_lane`, `override_lane`, `platform`, `before_all`, `before_each`, `after_all`, `after_each`, `error` and `desc`. Everything else you see in a Fastfile is either an **action** — a shipped unit of work such as `build_app` — or ordinary Ruby. ## What a lane declares A lane is one named, ordered sequence of actions. For the orchard spray-diary app, the Apple beta path reads: ```ruby platform :ios do desc "Archive the orchard spray-diary app and send it to Apple TestFlight" lane :beta do |options| sync_code_signing(type: "appstore") build_app(scheme: "SprayDiary") upload_to_testflight end end ``` Three details carry the whole idea: - `lane :beta` registers the block under the symbol `:beta`, and that symbol is the exact name a CI step will type. - The block parameter `options` is a hash of whatever the caller passed; it is always present, even when the caller passed nothing at all. - `desc`, written immediately above the lane, supplies the one-line description fastlane prints when it lists the file's lanes, so the entry points document themselves. The actions inside are fastlane's tools under their **canonical names**. `sync_code_signing` is the action the nickname `match` aliases, `build_app` is the action `gym` aliases, and `upload_to_testflight` is the action `pilot` aliases — all three are Apple-platform steps for the iOS build. Both spellings work in a Fastfile, but the canonical `verb_noun` name is what the action is really called, and it is the name worth saying out loud in an interview. ## Ordering, failure and the exit status Actions run in the written order, in a single Ruby process, sharing state. A value one action produces is readable by the next through fastlane's `lane_context` — `build_app` publishes the archived iOS artifact path as `SharedValues::IPA_OUTPUT_PATH`, and an upload action downstream picks it up without the lane restating a path. Failure is equally simple: the first action that raises **aborts the lane**. The remaining actions never run, the `error` hook fires if the file declares one, and the `fastlane` process exits non-zero — which is precisely how the surrounding CI step learns that the release failed. ## platform blocks change the name you invoke Wrapping lanes in `platform :ios do ... end` or `platform :android do ... end` scopes them, which is how one Fastfile can hold an Apple lane and a Google Play lane that share a name without colliding. | declaration | invoked as | |---|---| | `lane :beta` at the top level of the file | `fastlane beta` | | `lane :beta` inside `platform :ios` | `fastlane ios beta` | | `lane :beta` inside `platform :android` | `fastlane android beta` | That is the most common first-day surprise: a lane moved into a platform block stops answering to its bare name unless the file declares a default platform. ## How CI actually invokes one From the pipeline's side the contract is deliberately thin: 1. Check out the repository so the Fastfile is on disk next to the app. 2. Run exactly one command as the step's command — for example `fastlane ios beta`. 3. Provide configuration the lane reads from its environment, and any per-run values as lane parameters after the lane name. 4. Let the exit status decide the step: zero passes, non-zero fails the job. Everything about *how* the release happens hides behind that one lane name, and that is the point. The pipeline file stays a trigger plus one command; the release logic stays in the repository, reviewed with the app and runnable on a developer's machine with the identical command. When an interviewer asks why lanes exist at all, that is the answer: **one invocable name, one reviewed definition, identical locally and on CI.** ## What does not belong inside a lane - Pipeline concerns — what triggers a run, how stages are laid out, which jobs run in parallel — stay in the CI configuration, not in the Fastfile. - Credentials stay in the CI platform's secret storage and reach the lane as environment variables rather than being written into the Fastfile. - A lane that does five unrelated things is painful to retry; prefer several small lanes plus one lane that calls them in order. - Logic that is really about the Ruby language rather than the pipeline belongs in a helper, not smeared across the lane body.

  • The same lane name exists under both platform blocks in this Fastfile. How does fastlane decide which one runs?
    By the platform segment on the command line. `fastlane ios beta` resolves the lane registered inside `platform :ios`, and `fastlane android beta` the one inside `platform :android`. Without a platform segment fastlane looks for a top-level lane of that name, or the one under the file's declared default platform; if neither exists the invocation fails rather than guessing.
  • How does one action hand a value to the action that follows it in the same lane?
    Through fastlane's `lane_context`. Actions publish outputs under `SharedValues::` keys — `build_app` sets `SharedValues::IPA_OUTPUT_PATH` for the iOS archive it produced — and a later action in the same run reads that key by default. It is in-process state: it exists for the duration of one `fastlane` invocation and starts empty on the next.

saying these in an interview costs you the question

  • Thinks the Fastfile executes top to bottom like a shell script
  • Cannot say how a CI step selects one lane out of the file
  • Believes a lane keeps running after an action raises
  • Encodes the platform in the lane name instead of a platform block
  • Treats desc as a comment with no effect on anything