Deployment & CI/CD
GitHub Actions Workflows
What you'll learn
- Setting up PR validation and build/deploy workflows
- Using affected package detection to skip unchanged packages in CI
- Managing secrets for code signing and store uploads
- Releasing both platforms from a version tag
Prerequisites
- An existing Archipelago monorepo (see Monorepo Scaffolding)
- A GitHub repository with Actions enabled
- Store credentials ready (App Store Connect API key, Play Console service account)
Step 1: Choose GitHub at Generation Time
CI workflows are generated with the project. There is no separate generate command. The gitProvider variable of flutter_modular_monorepo (github by default, or gitlab) decides which one you get. With github you get a .github/ directory, with gitlab you get a .gitlab-ci.yml with the same jobs (stages test, guard, build, analyze, baseline).
Step 2: Understand the Generated Workflows
.github/
├── copilot-instructions.md
└── workflows/
├── ci.yml # Analyze + test: changed packages on develop PRs/pushes, everything on release PRs; require its ci-ok check
├── pr-checks.yml # Pro. Every PR: size guard, new-library check. Release PRs: APK/IPA size analysis, permission guard
├── build-android.yml # Reusable workflow (workflow_call) for Android builds
├── build-ios.yml # Reusable workflow (workflow_call) for iOS builds
├── release-mobile.yml # Tag push "mobile/v*": builds and deploys both platforms
└── update-baselines.yml # Pro. Manual: refreshes size and permission baselines (run on develop after a release)pr-checks.yml and update-baselines.yml run toolkit commands (size-guard check --changed-only, detect-new-library check, size-analyzer analyze, permission-guard android|ios, size-analyzer update-baseline, permission-guard update-baseline), so they need the Pro devtool bricks installed. See Monorepo Toolkit.
Step 3: PR Checks Workflow
pr-checks.yml runs on every pull request to develop or main; the APK/IPA jobs run only on PRs into main, release/* and hotfix/* PRs and manual runs (see CI test scope). Each job installs the toolkit and runs one command, for example:
size-guard:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dart-lang/setup-dart@v1
- run: dart pub get
working-directory: devtools/monorepo_toolkit
- run: dart run monorepo_toolkit size-guard check --changed-only
working-directory: devtools/monorepo_toolkitThe Android and iOS size-analysis jobs build the app, run size-analyzer analyze, and the permission-guard jobs compare the built APK/IPA against the committed baseline.
Step 4: Configure Secrets
Add the following secrets in your GitHub repository settings under Settings > Secrets and variables > Actions. The names match what release-mobile.yml passes to the reusable workflows:
| Secret | Purpose |
|---|---|
MATCH_GIT_URL | Git URL of your Match certificates repo |
MATCH_PASSWORD | Encryption password for Match |
APPLE_ID, TEAM_ID, ITC_TEAM_ID | Apple Developer account identifiers |
APP_IDENTIFIER | Bundle ID override (optional) |
APP_STORE_CONNECT_API_KEY_ID, APP_STORE_CONNECT_API_ISSUER_ID, APP_STORE_CONNECT_API_KEY_CONTENT | App Store Connect API key |
GOOGLE_PLAY_JSON_KEY_BASE64 | Base64-encoded Google Play service account JSON |
FIREBASE_ANDROID_APP_ID, FIREBASE_IOS_APP_ID | Firebase App Distribution app IDs (when distributing to Firebase) |
SLACK_WEBHOOK_URL | Optional build notifications |
Encode files to base64 for storage as secrets:
base64 -i path/to/play-store-key.json | pbcopyStep 5: Release Workflow
release-mobile.yml triggers on tags matching mobile/v*, extracts the version from the tag, and calls both reusable build workflows:
git tag mobile/v1.2.0
git push origin mobile/v1.2.0on:
push:
tags:
- "mobile/v*"
jobs:
build-android:
uses: ./.github/workflows/build-android.yml
with:
flavor: production
track: internal
build-ios:
uses: ./.github/workflows/build-ios.yml
with:
flavor: production
destination: testflightThe reusable workflows run the Fastlane lanes from Fastlane Setup. build-android.yml takes flavor, track (empty means Firebase distribution) and build_number. build-ios.yml takes flavor, destination (firebase, testflight or appstore) and build_number.
Step 6: Using Affected Detection in CI
The affected command is an Enterprise extension and is not wired into the generated workflows. To add it, use the commands from the Affected Packages guide:
- name: Analyze affected packages
run: dart run monorepo_toolkit affected analyze --base origin/develop
- name: Test affected packages
run: dart run monorepo_toolkit affected test --base origin/developThe affected brick also ships devtools/scripts/affected/ci-affected-matrix.yml.example, a ready-made dynamic matrix workflow.
Key Customization Points
| Customization | Where to Change |
|---|---|
| Trigger branches | on.pull_request.branches in pr-checks.yml |
| Release tag pattern | on.push.tags in release-mobile.yml |
| Flutter version | subosito/flutter-action version input |
| Affected base branch | --base flag of the affected command |
| Play Store track | track input passed from release-mobile.yml |
| iOS destination | destination input passed from release-mobile.yml |
Next Steps
- Configure Fastlane for store deployment lanes
- Set up build_prepare to strip debug packages from production-flavor builds