← Back to posts Cover image for Mastering CI/CD for Flutter: A Practical Guide to Fastlane and GitHub Actions

Mastering CI/CD for Flutter: A Practical Guide to Fastlane and GitHub Actions

· 5 min read
Weekly Digest

The Flutter news you actually need

No spam, ever. Unsubscribe in one click.

Chris
By Chris

Mastering CI/CD for Flutter: A Practical Guide to Fastlane and GitHub Actions

Automating your Flutter app’s build, test, and release process is a game-changer. It saves hours of manual work, reduces human error, and lets you ship updates with confidence. Yet, setting up a robust CI/CD pipeline for both Android and iOS often feels daunting. You need to handle code signing, environment secrets, platform-specific builds, and store submissions—all while keeping your workflow maintainable.

This guide walks you through a practical setup using Fastlane to automate builds and GitHub Actions to orchestrate your pipeline. By the end, you’ll have a working foundation you can adapt for your own projects.

Why Fastlane + GitHub Actions?

Fastlane is a powerful automation tool that abstracts away the platform-specific complexities of building and deploying mobile apps. With it, you can define simple commands like flutter build ipa or upload_to_testflight in a reproducible way.

GitHub Actions provides a flexible, integrated CI/CD environment. It’s free for public repositories and offers generous minutes for private ones. Combining these tools gives you a pipeline that runs on every commit, ensuring your app is always in a shippable state.

Step 1: Setting Up Fastlane

First, add Fastlane to your project. Ensure you have Ruby installed, then from your project’s root directory:

# Install the Fastlane gem
gem install fastlane

# Navigate to your Android directory and initialize Fastlane
cd android
fastlane init

# Do the same for iOS
cd ../ios
fastlane init

During initialization, Fastlane will guide you through setting up App Store Connect and Google Play credentials. For now, you can skip the setup and manually create the configuration files.

The core of Fastlane is the Fastfile. Here’s a simple example for iOS that builds and uploads to TestFlight:

# ios/fastlane/Fastfile
default_platform(:ios)

platform :ios do
  desc "Build the iOS app and upload to TestFlight"
  lane :beta do
    # Increment the build number
    increment_build_number(
      build_number: latest_testflight_build_number + 1
    )

    # Build the app with Flutter
    sh("cd ../ && flutter build ipa --release --no-codesign")

    # Upload to TestFlight
    upload_to_testflight(
      ipa: "../build/ios/ipa/YourApp.ipa",
      skip_waiting_for_build_processing: true
    )
  end
end

For Android, a similar lane can build an App Bundle and promote it to an internal track:

# android/fastlane/Fastfile
default_platform(:android)

platform :android do
  desc "Build and deploy to Google Play Internal Track"
  lane :internal do
    # Build the app bundle with Flutter
    sh("cd ../ && flutter build appbundle --release")

    # Upload to Google Play
    upload_to_play_store(
      track: 'internal',
      aab: '../build/app/outputs/bundle/release/app-release.aab'
    )
  end
end

Step 2: Handling Secrets and Signing

A common stumbling block is managing signing credentials and API keys. Never commit these to your repository. Use environment variables or encrypted secrets.

With Fastlane, you can use the dotenv gem to load environment-specific variables. Create a .env.default file (checked into version control) with placeholder values and a .env file (ignored by Git) with real secrets.

For GitHub Actions, use the repository secrets settings. You can add keys like MATCH_PASSWORD, APP_STORE_CONNECT_API_KEY, and GOOGLE_PLAY_JSON_KEY_DATA.

Step 3: Creating the GitHub Actions Workflow

Now, let’s tie it all together with a GitHub Actions workflow. This pipeline will run your tests, build the app, and deploy it based on the branch.

Create a file at .github/workflows/cicd.yml:

name: CI/CD Pipeline

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
        with:
          channel: 'stable'
      - run: flutter pub get
      - run: flutter test

  build-and-deploy:
    needs: test
    runs-on: macos-latest
    if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
    steps:
      - uses: actions/checkout@v4

      - name: Set up Flutter
        uses: subosito/flutter-action@v2

      - name: Install Fastlane
        run: gem install fastlane

      - name: Build and Deploy Android
        if: github.ref == 'refs/heads/develop'
        env:
          GOOGLE_PLAY_JSON_KEY_DATA: ${{ secrets.GOOGLE_PLAY_JSON_KEY_DATA }}
        run: |
          cd android
          bundle exec fastlane internal

      - name: Build and Deploy iOS
        if: github.ref == 'refs/heads/develop'
        env:
          APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
        run: |
          cd ios
          bundle exec fastlane beta

This workflow runs tests on every push and pull request. When a push is made to the develop branch, it triggers a deployment to the testing tracks (Google Play Internal and TestFlight). You can extend this to deploy to production from the main branch by adding another condition.

Common Pitfalls and Best Practices

  1. Code Signing for iOS: Use Fastlane’s match to manage your certificates and provisioning profiles. It syncs them across your team and CI system, eliminating “code signing” headaches.
  2. Build Caching: GitHub Actions can be slow if you install dependencies every time. Cache your Flutter dependencies and Ruby gems to speed up runs.
  3. Conditional Deployments: As shown in the workflow, use branch conditions to control where your builds go. This prevents accidental production releases.
  4. Keep Fastfiles DRY: If you have shared steps between Android and iOS, consider writing a custom Fastlane action in Ruby or calling a shared shell script.

Wrapping Up

Implementing CI/CD with Fastlane and GitHub Actions might require some initial setup, but the payoff is immense. You gain consistent builds, automated testing, and one-command deployments. Start with the basic pipeline above, then iterate based on your team’s needs. Automate the tedious parts, and focus on what matters—building a great Flutter app.

Remember, the goal is not just automation, but reliable and repeatable automation. Once your pipeline is in place, you’ll wonder how you ever shipped apps without it.

This blog is produced with the assistance of AI by a human editor. Learn more

Related Posts

Cover image for Demystifying Dart's Reflection: When to Use Code Generation for Powerful Flutter Features

Demystifying Dart's Reflection: When to Use Code Generation for Powerful Flutter Features

Dart's lack of full runtime reflection in Flutter often frustrates developers used to languages like C#, limiting dynamic tool building. This post will clarify why Flutter restricts reflection (tree-shaking benefits), explain the `dart:mirrors` library's role, and most importantly, provide practical strategies for achieving similar powerful capabilities through compile-time code generation and annotations, with real-world examples.

Cover image for Fixing Flutter ANR Issues: Strategies for Unblocking the Main Thread

Fixing Flutter ANR Issues: Strategies for Unblocking the Main Thread

App Not Responding (ANR) errors plague many Flutter apps, often misdiagnosed as general slowness. This post will delve into identifying and resolving ANRs by focusing on common causes of main thread blocks, providing practical tools and techniques for ensuring a smooth, responsive user experience.

Cover image for Mastering CI/CD for Flutter: A Practical Guide to Fastlane and GitHub Actions

Mastering CI/CD for Flutter: A Practical Guide to Fastlane and GitHub Actions

Implementing robust Continuous Integration and Continuous Deployment (CI/CD) is essential for shipping Flutter apps efficiently, yet many developers struggle with setting up reliable pipelines for Android and iOS. This post will provide a practical guide to leveraging Fastlane and GitHub Actions to automate builds, testing, and deployments, addressing common challenges and sharing best practices for a streamlined release workflow.