Blog

Flutter CI/CD for App Store & Play Store (GitHub Actions + Fastlane)

A production overview of Flutter CI/CD pipelines for iOS and Android — GitHub Actions, Fastlane, code signing, TestFlight, and Play Store tracks from real release experience.

S

Sagar R Anghan

2026-09-11 • 5 min read

Flutter CI/CD for App Store & Play Store (GitHub Actions + Fastlane)

Manual releases do not scale.
The third time you forget to bump the build number, upload the wrong provisioning profile, or ship a debug Firebase config to production, you start looking for automation.

CI/CD for Flutter mobile apps is harder than for a web deploy — you are dealing with code signing, macOS runners for iOS, keystore management, and two separate store consoles with different rules. But once the pipeline is in place, every release becomes repeatable instead of a Friday-night ritual.

This is an overview of how I set up Flutter CI/CD for production apps using GitHub Actions and Fastlane — not a copy-paste tutorial, but the decisions and pitfalls that matter when you are actually shipping to the App Store and Google Play.

CI/CD does not replace release judgment.
It removes repeatable mistakes so you can focus on store compliance and rollout strategy.

Why Flutter CI/CD Is Worth the Setup Cost

Without automation, release day typically involves:

  • A developer with the only Mac that can archive iOS builds
  • Manually editing version numbers in pubspec.yaml
  • Uploading AAB/IPA files through browser consoles
  • Hoping nobody committed secrets or debug flags

With a solid pipeline:

  • Every merge to main produces a verified release build
  • TestFlight and internal Play tracks update automatically
  • Version bumps are consistent and traceable in git
  • Signing credentials live in secure storage, not someone's laptop

Apps like Die Friedliche Geburt and Joii needed reliable release cadence across iOS and Android — wellness and mental health products where a broken release blocks users from content they depend on. Automation is how you keep that cadence without burning out the team.

The Stack: GitHub Actions + Fastlane

There are other options (Codemagic, Bitrise, self-hosted runners). GitHub Actions + Fastlane is what I use most often because:

  • GitHub Actions — already where the code lives; good enough for most Flutter teams
  • Fastlane — mature mobile release tooling for both iOS and Android with a large plugin ecosystem

You do not need both on day one. A reasonable progression:

  1. CI only — lint, test, and build APK/AAB on every PR
  2. CD to internal tracks — auto-deploy to TestFlight internal / Play internal testing
  3. CD to production — manual approval gate, then promote to App Store / Play production

Planning to build a Flutter app?

I help startups design and build scalable mobile apps with clean architecture, Firebase, and store-ready delivery.

Pipeline Stages That Actually Matter

Stage 1: Pull request checks

Run on every PR — fast feedback, no signing required:

# Conceptual steps — adapt to your repo
- flutter pub get
- flutter analyze
- flutter test
- flutter build apk --release  # Android-only PR validation

Keep PR pipelines under 10–15 minutes where possible. Developers ignore slow CI.

Stage 2: Release build on merge

Triggered on merge to release/* or main (your branching strategy may vary):

  • flutter build appbundle for Android
  • flutter build ipa for iOS (requires macOS runner)
  • Upload artifacts to GitHub Actions storage for manual inspection if needed

Stage 3: Store deployment via Fastlane

Fastlane lanes handle the store-specific work:

Android (supply):

  • Upload AAB to Play Console
  • Target a track: internalclosedproduction
  • Attach release notes from git tag or CHANGELOG

iOS (deliver / pilot):

  • Upload IPA to App Store Connect
  • Distribute to TestFlight testers
  • Optionally submit for review (I usually keep review submission manual)

Code Signing: Where Most Pipelines Break

Signing is the hard part. Everything else is YAML.

Android

  • Store your upload keystore as a base64-encoded secret in GitHub Actions (or use Google Play App Signing and keep the upload key secure)
  • Write key.properties and the keystore file in the CI job from secrets — never commit them
  • Use Play App Signing so Google holds the app signing key; you only manage the upload key

iOS

  • Export certificates and provisioning profiles as encrypted secrets, or use Fastlane Match to sync signing assets from a private git repo
  • macOS runners (macos-latest) are required for flutter build ipa
  • Apple Developer account credentials: use App Store Connect API keys (preferred) instead of Apple ID passwords with 2FA gymnastics

If your CI pipeline only builds Android, you still have half a release process.
Budget for macOS runner minutes and iOS signing setup from the start.

A Minimal Fastlane Structure

Typical layout in a Flutter repo:

android/fastlane/Fastfile
android/fastlane/Appfile
ios/fastlane/Fastfile
ios/fastlane/Appfile

Example Android lane concept:

lane :internal do
  upload_to_play_store(
    track: 'internal',
    aab: '../build/app/outputs/bundle/release/app-release.aab',
    skip_upload_metadata: true,
    skip_upload_images: true,
    skip_upload_screenshots: true
  )
end

Example iOS lane concept:

lane :beta do
  build_app(
    workspace: "Runner.xcworkspace",
    scheme: "Runner"
  )
  upload_to_testflight(
    skip_waiting_for_build_processing: true
  )
end

Fastlane handles the store API calls; GitHub Actions orchestrates when lanes run.

GitHub Actions Workflow Patterns

Separate workflows for platform vs. combined

Option A — one workflow, matrix strategy:

strategy:
  matrix:
    platform: [android, ios]

Option B — separate workflow files:

  • .github/workflows/android-release.yml
  • .github/workflows/ios-release.yml

I prefer separate files for mobile. iOS jobs need macOS runners (more expensive, slower) and fail for different reasons than Android. Splitting keeps debugging saner.

Secrets you will need

SecretPlatformPurpose
ANDROID_KEYSTORE_BASE64AndroidUpload keystore
ANDROID_KEY_ALIAS / passwordsAndroidSigning
PLAY_STORE_JSON_KEYAndroidPlay Console API
MATCH_PASSWORD / certs repoiOSCode signing via Match
APP_STORE_CONNECT_API_KEYiOSTestFlight / App Store upload

Store these in GitHub Environment secrets with protection rules for production deployments.

Environment Flavors and CI

Production CI/CD assumes you have flavors or --dart-define flags separating dev, staging, and production Firebase projects.

Checklist for CI environments:

  • Production builds use production Firebase config — not dev
  • API base URLs injected at build time, not hardcoded
  • Analytics and crash reporting keys match the target environment
  • App name / bundle ID suffix distinguishes staging from production on device

If flavors are new to your project, nail them before automating releases. Automating the wrong config is worse than manual uploads.

For Firebase production readiness beyond CI, see Flutter + Firebase Production Checklist.

Release Gates: Do Not Auto-Ship to Production on Day One

Automating TestFlight and Play internal tracks is low risk. Automating production rollout on every merge is how you ship a regression to 100% of users at 2 AM.

Recommended gates:

  1. Internal track auto-deploy on merge to release branch
  2. QA sign-off on internal build (manual checklist)
  3. Manual workflow dispatch or approval environment for production
  4. Staged rollout on Play Store (start at 10%, monitor crash rates)
  5. Phased release on App Store (optional but useful for large user bases)

The App Store + Play Store Release Checklist covers privacy manifests, data safety forms, and review requirements that CI cannot validate — those stay human checks before production promotion.

Common Failures and Fixes

ProblemLikely causeFix
iOS build fails on CI onlyProvisioning profile mismatchMatch certs; verify bundle ID
Android upload rejectedVersion code not incrementedAutomate version bump in CI
Firebase wrong project in releaseMissing --dart-define or flavor flagAdd env check step before build
TestFlight upload hangsApple processing delayskip_waiting_for_build_processing: true
Play Store rejects AABTarget SDK too oldUpdate compileSdk / target API in CI
CI secrets leaked in logsEchoing signing filesMask secrets; audit workflow output

What CI/CD Does Not Replace

Automation handles build and upload. It does not handle:

  • Store listing copy and screenshots — still manual in App Store Connect / Play Console (unless you automate metadata via Fastlane, which adds complexity)
  • Privacy nutrition labels and data safety forms — human accuracy required
  • Review rejection triage — Apple and Google still reject apps for policy reasons CI cannot predict
  • Rollback decisions — you need monitoring (Firebase Crashlytics, Sentry) and a human call to halt rollout

For architecture that survives frequent releases, see Best Architecture for Scalable Flutter Apps.

When to Invest in CI/CD

Set up CI (lint + test + build) from week one. It is cheap and catches regressions early.

Add CD to internal tracks before your first beta user. Manual TestFlight uploads get old fast.

Add production CD only when you have monitoring, a rollback plan, and enough release history to trust the pipeline.

If you are hiring a Flutter freelancer to ship your MVP, ask whether they will leave you with a working pipeline — not just an app that only builds on their machine. That handoff detail belongs in every freelancer evaluation.

Need Help Setting Up Release Automation?

I set up Flutter CI/CD pipelines as part of production engagements — GitHub Actions, Fastlane, signing, and internal track deployment — so teams can ship confidently after handoff.

Review Flutter app development services and case studies for the kind of production work I take on. If you want help designing a release pipeline for your app, book a free consultation or send a message.

Have an app idea?

Let's build something scalable together — from MVP through store release.

See case studies for production examples.