Learn about the Fastfile, the heart of your fastlane configuration
The Fastfile is the core configuration file for fastlane. It’s where you define lanes, actions, and automation workflows for your mobile app development process. Written in Ruby, the Fastfile provides a simple DSL (Domain Specific Language) that makes it easy to automate building, testing, and releasing your apps.
A Fastfile is a Ruby file located in the fastlane/ directory of your project. It contains all the automation logic for your project, organized into lanes. Think of it as a recipe book for your app’s build and deployment processes.
The Fastfile is evaluated as Ruby code, which means you have access to the full power of Ruby including variables, conditionals, loops, and methods.
Here’s a simple Fastfile structure from the fastlane source code:
# Simple lane definitionlane :test do scan(scheme: "MyApp")end# Lane with descriptiondesc "Build the app for release"lane :build do gym(scheme: "MyApp", export_method: "app-store")end
You can organize lanes by platform using platform blocks:
platform :ios do desc "Build iOS app" lane :build do gym(scheme: "MyApp-iOS") end lane :test do scan(scheme: "MyApp-iOS") endendplatform :android do desc "Build Android app" lane :build do gradle(task: "assembleRelease") end lane :test do gradle(task: "test") endendplatform :mac do desc "Build macOS app" lane :build do gym(scheme: "MyApp-Mac") endend
iOS
Android
Cross-platform
platform :ios do lane :beta do build_app(scheme: "MyApp") upload_to_testflight endend
platform :android do lane :beta do gradle(task: "assembleRelease") upload_to_play_store(track: "beta") endend
# Lanes without a platform block work for all platformslane :setup do ensure_git_status_clean cocoapodsend
# Public lane (can be called from CLI)lane :deploy do # lane implementationend# Private lane (internal use only)private_lane :prepare_build do # lane implementationend# Override lane (useful when importing Fastfiles)override_lane :test do # new implementationend
Fastfile supports hooks that run at specific points in your workflow:
# Runs before all lanes in this platformbefore_all do |lane, options| ensure_git_status_clean cocoapodsend# Runs before each lanebefore_each do |lane, options| UI.message("Starting lane: #{lane}")end# Runs after all lanes complete successfullyafter_all do |lane, options| notification(message: "Success!")end# Runs after each laneafter_each do |lane, options| UI.message("Finished lane: #{lane}")end# Runs when an error occurserror do |lane, exception, options| slack( message: "Error in lane #{lane}: #{exception.message}", success: false )end
You can split your configuration across multiple files:
# Import a local Fastfileimport "./CustomFastfile"# Import from a relative pathimport "../shared/Fastfile"# Import from a git repositoryimport_from_git( url: "https://github.com/company/fastlane-config.git", branch: "main", path: "fastlane/Fastfile")
# Use fastlane_require to auto-install missing gemsfastlane_require 'xcodeproj'fastlane_require 'colorize'# Then use the gemslane :example do project = Xcodeproj::Project.open("MyApp.xcodeproj") UI.success("Project loaded!".green)end
Use platform blocks to keep iOS, Android, and Mac lanes separate and organized. This prevents naming conflicts and makes your Fastfile easier to navigate.
platform :ios do lane :release do # iOS-specific release endendplatform :android do lane :release do # Android-specific release endend
Use Private Lanes
Extract common functionality into private lanes to keep your code DRY (Don’t Repeat Yourself):
lane :beta do prepare_release build_app upload_to_testflightendlane :production do prepare_release build_app upload_to_app_storeendprivate_lane :prepare_release do ensure_git_status_clean increment_build_number commit_version_bumpend
Add Descriptions
Always add descriptions to your lanes. They show up in fastlane lanes and serve as documentation:
desc "Deploy a new version to the App Store"desc "This will also make sure the profile is up to date"lane :release do # implementationend
Use Error Handling
Implement error blocks to handle failures gracefully:
error do |lane, exception| # Clean up resources reset_git_repo # Send notifications slack( message: "#{lane} failed: #{exception.message}", success: false )end
Environment Variables
Use environment variables for sensitive data:
lane :deploy do api_key = ENV["APP_STORE_API_KEY"] upload_to_app_store( api_key: api_key, skip_screenshots: true )end
lane :build do # Some actions set shared values build_app(scheme: "MyApp") # Access the shared value ipa_path = lane_context[SharedValues::IPA_OUTPUT_PATH] UI.message("IPA created at: #{ipa_path}")end
Here’s a production-ready example based on fastlane’s own Fastfile:
fastlane_require 'xcodeproj'skip_docs # Don't generate README.md# Runs before all lanesbefore_all do |lane| ensure_git_status_clean unless lane == :testend# Error handlingerror do |lane, exception| slack( channel: "#builds", message: "#{lane} failed: #{exception.message}", success: false )endplatform :ios do desc "Run all tests" lane :test do scan( scheme: "MyApp", devices: ["iPhone 14", "iPad Pro (12.9-inch)"] ) end desc "Submit a new beta build to TestFlight" lane :beta do increment_build_number build_app(scheme: "MyApp") upload_to_testflight( skip_waiting_for_build_processing: true ) commit_version_bump(message: "Version Bump by fastlane") push_to_git_remote end desc "Deploy a new version to the App Store" lane :release do capture_screenshots build_app(scheme: "MyApp") upload_to_app_store( submit_for_review: true, automatic_release: false, force: true ) endendplatform :android do desc "Submit a new beta build to Play Console" lane :beta do gradle(task: "assembleRelease") upload_to_play_store( track: "beta", skip_upload_apk: true ) endend