You finish setting up Fastlane, everything looks fine — then on release day, fastlane beta blows up with a certificate error you've never seen before. If that sounds familiar, you're not alone. Managing Fastlane configs across multiple apps is one of those tasks that's straightforward in theory but surprisingly fragile in practice.
What I've found is that pairing Claude Code with Fastlane changes this dynamic significantly. Claude Code understands Fastfile syntax well enough to suggest targeted fixes, reads fastlane env output to identify missing variables, and explains why a particular configuration is failing — not just what to change. This guide walks through building a dual-platform deploy pipeline using both tools together.
How Claude Code and Fastlane Divide the Work
Before diving into code, it helps to be clear about what each tool is responsible for.
Fastlane handles:
- Build, sign, and archive execution (wrapper around
xcodebuild/ Gradle) - Automatic uploads to App Store Connect / Google Play Developer Console
- Screenshot automation (
snapshot/screengrab) - Certificate and provisioning profile management (
match)
Claude Code handles:
- Generating Fastfile boilerplate and explaining existing configurations
- Diagnosing error messages and suggesting targeted Fastfile fixes
- Spotting missing or mistyped environment variables
- Optimizing
Appfilesettings and App Store Connect API key setup
Think of Claude Code as a knowledgeable dev partner who's already read the Fastlane docs — so you don't have to dig through them every time something breaks.
Environment Prerequisites
Before starting, confirm you have:
- Xcode 26 / Android Studio Meerkat or later
- Ruby 3.2+ (
ruby --version) - Fastlane 2.225.0+ (
fastlane --version) - App Store Connect API key (
.p8file + Key ID + Issuer ID) - Google Play service account JSON (Android only)
If Fastlane isn't installed yet, the fastest path is to let Claude Code handle the initial setup from bundle init:
# Run from project root
claude "Set up Fastlane for this iOS project.
Use Ruby bundler and create a Gemfile.
Manage App Store Connect API key credentials via a .env file."This single prompt generates Gemfile, fastlane/Appfile, and fastlane/Fastfile stubs, plus a .env.example that lists every required variable with placeholder values.
Fastfile Design: iOS
Here's a working iOS Fastfile generated by Claude Code. The critical piece is using App Store Connect API authentication, which eliminates the need to manage certificates manually on each machine.
# fastlane/Fastfile (iOS)
default_platform(:ios)
platform :ios do
before_all do
# Load env vars from .env file (requires dotenv gem)
Dotenv.load(".env")
end
desc "Build and upload to TestFlight"
lane :beta do
# App Store Connect API auth — no certificate file needed
app_store_connect_api_key(
key_id: ENV["ASC_KEY_ID"],
issuer_id: ENV["ASC_ISSUER_ID"],
key_content: ENV["ASC_KEY_CONTENT"], # base64-encoded .p8 content
is_key_content_base64: true
)
# Sync certificates via match (read-only, pulls from Git repo)
match(type: "appstore", readonly: true)
# Auto-increment build number based on latest TestFlight build
increment_build_number(
build_number: latest_testflight_build_number + 1
)
# Build and archive
build_app(
scheme: ENV["SCHEME_NAME"],
export_method: "app-store",
output_directory: "./build",
output_name: "MyApp.ipa"
)
# Upload to TestFlight
upload_to_testflight(
skip_waiting_for_build_processing: true,
changelog: "Auto-deploy: #{Time.now.strftime('%Y-%m-%d %H:%M')}"
)
end
desc "Submit to App Store for review"
lane :release do
beta # reuse beta lane for the build
upload_to_app_store(
submit_for_review: true,
automatic_release: false, # keep manual publish control
force: true # skip screenshot re-upload
)
end
endOne detail worth calling out: is_key_content_base64: true. You can reference the .p8 file by path, but passing it as a base64-encoded environment variable is safer in CI environments. To generate the encoded string:
# Encode .p8 file content to single-line base64
base64 -i AuthKey_XXXXXXXXXX.p8 | tr -d '\n'Fastfile Design: Android
For Android, the focus shifts to Google Play API auth and keystore management.
# Add to fastlane/Fastfile
platform :android do
desc "Upload to internal test track"
lane :beta do
gradle(
task: "bundle",
build_type: "Release",
project_dir: "android/",
properties: {
"android.injected.signing.store.file" => ENV["KEYSTORE_PATH"],
"android.injected.signing.store.password" => ENV["KEYSTORE_PASSWORD"],
"android.injected.signing.key.alias" => ENV["KEY_ALIAS"],
"android.injected.signing.key.password" => ENV["KEY_PASSWORD"]
}
)
upload_to_play_store(
track: "internal",
aab: "android/app/build/outputs/bundle/release/app-release.aab",
json_key: ENV["GOOGLE_PLAY_JSON_KEY_PATH"]
)
end
endPassing keystore passwords through environment variables means you never need keystore.properties in your repository — a small but meaningful security improvement.
Real-World Debugging with Claude Code
Certificate and provisioning issues are where most Fastlane pipelines break. Here's how I debug these with Claude Code in practice.
Say you hit this common error:
[!] Your account already has a valid certificate for this
bundle identifier stored locally. However, the fastlane
provisioning profile was regenerated.
Paste the full error into a Claude Code prompt along with your current Fastfile:
claude "I ran fastlane beta and got this error. How should I fix it?
[paste error output here]
Here's my current Fastfile:
[paste Fastfile content here]"Claude Code will give you the two most likely fixes — adding force_for_new_devices: true or switching to readonly: false — and explain which situation calls for which. That context is what makes the difference between blindly copying a Stack Overflow answer and actually understanding the fix.
.env File Design and Secret Management
# .env.example (commit this to the repo as a template)
# App Store Connect API
ASC_KEY_ID=YOUR_KEY_ID
ASC_ISSUER_ID=YOUR_ISSUER_ID
ASC_KEY_CONTENT=BASE64_ENCODED_P8_CONTENT
# App config
SCHEME_NAME=MyApp
BUNDLE_ID=com.example.myapp
# Android keystore
KEYSTORE_PATH=/path/to/release.keystore
KEYSTORE_PASSWORD=YOUR_KEYSTORE_PASSWORD
KEY_ALIAS=release
KEY_PASSWORD=YOUR_KEY_PASSWORD
# Google Play
GOOGLE_PLAY_JSON_KEY_PATH=/path/to/service-account.jsonAdd .env to .gitignore and only commit .env.example. When you specify this pattern upfront in your Claude Code prompt, the generated Fastfile will consistently use ENV[] references throughout — no hardcoded values to accidentally expose.
Your First Run
Once your environment is set up, run bundle exec fastlane beta from your project root. If it fails, paste the full output into Claude Code. Fastlane's setup curve is front-loaded — getting the first successful run through is the hardest part. After that, it tends to stay stable.
For deeper coverage of App Store Connect API and the full release pipeline, see Claude Code × App Store Connect API: Complete Automated iOS/Android Release Pipeline Guide. If you want to integrate testing before the release step, Claude Code iOS Testing with XCTest and Swift Testing covers the full test automation side.