DevOps

Mobile DevOps at Scale: Automating Flutter Releases with Fastlane & GitHub Actions

A complete guide to automating Flutter deployments. Set up Fastlane Match for code signing, GitHub Actions for cloud builds, and Firebase App Distribution for QA testing.

Sachin Sharma
Sachin SharmaCreator
Feb 12, 2026
5 min read
Mobile DevOps at Scale: Automating Flutter Releases with Fastlane & GitHub Actions
Featured Resource
Quick Overview

A complete guide to automating Flutter deployments. Set up Fastlane Match for code signing, GitHub Actions for cloud builds, and Firebase App Distribution for QA testing.

Mobile DevOps at Scale: Automating Flutter Releases with Fastlane & GitHub Actions

Scenario: It's Friday, 5 PM. Your PM asks: "Can we ship that hotfix to the App Store?" You sigh.

  1. 2.
    Open Xcode.
  2. 4.
    Increment Build Number.
  3. 6.
    Archive. (Wait 10 mins).
  4. 8.
    Upload. (Wait 15 mins).
  5. 10.
    Login to App Store Connect.
  6. 12.
    Select Build.
  7. 14.
    Submit for Review.

You just wasted 30 minutes of your life. And if you forgot to run tests? You just shipped a crash.

This ends today.

Over the last 5 years, I have built pipelines that turn that 30-minute manual hell into a single git command: git tag v1.0.1 && git push --tags

The robot handles the rest.

In this deep dive, we will configure:

  1. 2.
    Fastlane for local automation.
  2. 4.
    Match for code signing (the nightmare of iOS dev).
  3. 6.
    GitHub Actions for cloud execution.
  4. 8.
    Firebase App Distribution for QA.

Part 1: Fastlane (The Automation Engine)

Fastlane is a set of Ruby scripts that wrap the ugly xcodebuild and gradle commands.

Installation:

bash
brew install fastlane cd android && fastlane init cd ios && fastlane init

iOS Configuration (ios/fastlane/Fastfile)

We define "Lanes". A lane is a workflow.

ruby
default_platform(:ios) platform :ios do desc "Push a new beta build to TestFlight" lane :beta do increment_build_number(xcodeproj: "Runner.xcodeproj") build_app(workspace: "Runner.xcworkspace", scheme: "Runner") upload_to_testflight end end

Now, running fastlane ios beta does everything.


Part 2: The Code Signing Nightmare (Fastlane Match)

The #1 reason CI/CD fails on iOS is Certificates and Provisioning Profiles. "Certificate not found in keychain". "Profile doesn't match bundle ID".

The Solution: Fastlane Match. It stores your certificates encrypted in a private Git repository.

  1. 2.
    Create a private repo: my-company/certificates.
  2. 4.
    Run fastlane match init.
  3. 6.
    Run fastlane match appstore.
  4. 8.
    Run fastlane match development.

Now, your certificates live in cloud storage (Git). On your CI server (GitHub Actions), you just run "Match", pass the decryption password, and it installs the certs into the temporary keychain.

Zero manual keychain Access.


Part 3: Android Configuration (android/fastlane/Fastfile)

Android is easier (just a Keystore), but we still need to automate the Play Store upload.

first, perform json_key_file setup for Google Play Console API access.

ruby
platform :android do desc "Deploy to Play Store Internal Track" lane :internal do gradle(task: "bundle", build_type: "Release") upload_to_play_store(track: "internal", json_key: "play-store-creds.json") end end

Part 4: Managing Secrets (The .env Approach)

Never commit play-store-creds.json or passwords to Git. Use Environment Variables.

In both Fastfiles:

ruby
json_key_file(ENV["GOOGLE_JSON_KEY_FILE"]) store_password(ENV["ANDROID_STORE_PASSWORD"]) key_password(ENV["ANDROID_KEY_PASSWORD"])

In GitHub Actions, we will inject these secrets.


Part 5: GitHub Actions (The Cloud Runner)

Now we move the execution from your laptop to the cloud.

Create .github/workflows/deploy.yml:

yaml
name: Deploy to App Stores on: push: tags: - 'v*' # Trigger on version tags (v1.0.0) jobs: deploy_ios: runs-on: macos-latest # Expensive, but required for Xcode steps: - uses: actions/checkout@v4 - name: Setup Flutter uses: subosito/flutter-action@v2 with: channel: 'stable' - name: Install Dependencies run: flutter pub get - name: Decrypt Secrets run: echo "$GOOGLE_JSON_KEY" > android/key.json env: GOOGLE_JSON_KEY: ${{ secrets.GOOGLE_JSON_KEY }} - name: Fastlane Match (Install Certs) working-directory: ios run: fastlane match appstore --readonly env: MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }} - name: Build & Deploy iOS working-directory: ios run: fastlane beta env: APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_API_KEY }} deploy_android: runs-on: ubuntu-latest # Cheaper/Faster than Mac steps: - uses: actions/checkout@v4 - uses: subosito/flutter-action@v2 - name: Build & Deploy Android working-directory: android run: fastlane internal

Part 6: Firebase App Distribution (For QA)

TestFlight takes 20-30 minutes "processing". Play Store Internal takes 2-4 hours.

If you just want to show the app to your QA team, use Firebase App Distribution. It is instant.

Add a lane:

ruby
lane :qa do flutter_build_ipa firebase_app_distribution( app: "1:123456789:ios:xxxxxx", testers: "qa-team@company.com", release_notes: "New feature: Dark Mode" ) end

This sends an email to your QA team immediately with a "Download" button.


Part 7: Versioning Strategy

Don't manually edit pubspec.yaml version. Automate it.

  1. 2.
    Use cider (a Dart tool for manipulating pubspec).
  2. 4.
    In CI, extract version from Git Tag.
    • Tag: v1.2.3 -> Version: 1.2.3.
    • Build Number: github.run_number.
yaml
- name: Update Version run: | cider version ${{ github.ref_name }} cider build ${{ github.run_number }}

Conclusion: The ROI of DevOps

Setting this up takes 2 full days. It is painful. You will fight with Ruby versions. You will fight with Apple Permissions.

But once it works? You save 4 hours per release. If you release weekly, that is 200 hours a year. That is 5 weeks of vacation.

Do not be the developer who manually archives builds. Be the engineer who pushes a tag and goes to get coffee.

Resources


About the Author: Sachin Sharma is a Mobile DevOps expert. He has managed CI/CD pipelines for apps with 10M+ downloads and believes that manual releases are a bug.

Sachin Sharma

Sachin Sharma

Software Developer & Mobile Engineer

Building digital experiences at the intersection of design and code. Sharing weekly insights on engineering, productivity, and the future of tech.