| name | cicd-setup |
| description | Set up CI/CD pipelines for Flutter app builds and releases using Codemagic (priority) or GitHub Actions. Use this skill when the user asks about Flutter CI/CD, automated builds, Codemagic setup, GitHub Actions for Flutter, code signing automation, build pipelines, or deploying Flutter apps through CI. Also triggers on: 'automate my builds', 'set up continuous integration', 'pipeline for Flutter', 'codemagic.yaml', 'workflow for Flutter', or any mention of automating Flutter app distribution. |
CI/CD Pipeline Setup for Flutter
This skill configures automated build, test, and deployment pipelines for Flutter mobile apps. It produces three workflows that cover the full release lifecycle.
Three Workflows
Every Flutter CI/CD setup needs these three workflows, regardless of platform:
- PR Quality Gate — runs on pull requests, blocks merge if quality checks fail
- Android Pipeline — builds, signs, and distributes Android artifacts per environment
- iOS Pipeline — builds, signs, and distributes iOS artifacts per environment
Platform Selection
GitHub Actions + Custom Runners (recommended when you already have CI/CD infra):
- Read
references/github-actions.md for complete workflow files
- If your org already uses custom runners (Blacksmith, Buildjet, self-hosted), use them for Flutter too
- Add Flutter via
subosito/flutter-action@v2 — works on any Ubuntu runner
- Path filtering for monorepo setups
- Same dashboard, secrets, and billing as your existing CI/CD
- Signing: manual (keystore in secrets, key.properties generated in CI)
GitHub Actions + GitHub-hosted runners (starting from scratch, budget-conscious):
- Read
references/github-actions.md for complete workflow files
- 2000 free Linux minutes/month, 200 macOS minutes
- Larger action ecosystem but slower than custom runners
- Good for small projects without existing CI infra
Codemagic (recommended for iOS releases or teams without CI/CD):
- Read
references/codemagic.md for the complete codemagic.yaml configuration
- Native Flutter support — no Docker images or custom setup
- Built-in code signing UI for both Android and iOS
- Mac Mini M2 instances for iOS builds — no macOS runner management
- 500 free build minutes/month on the free tier
- Best value when you need iOS builds without managing macOS infrastructure
Common Architecture
Both platforms share the same logical architecture. The differences are in YAML syntax and platform-specific features.
Environment Detection
Pipelines detect the target environment from the branch name:
| Branch | Environment | Distribution | Signing | Obfuscation |
|---|
develop | dev | Firebase App Distribution | Debug or unsigned | No |
staging | staging | Firebase App Distribution / TestFlight | Release signed | No |
production | production | Google Play / App Store | Release signed | Yes |
Config Injection Pattern
Never commit secrets to the repository. Use template-based injection:
Template file (committed): lib/core/env/env_ci.dart
class EnvConfig {
static const String baseUrl = '<<BASE_URL>>';
static const String apiKey = '<<API_KEY>>';
static const String environment = '<<ENV_NAME>>';
}
Generator script (committed): scripts/generate_config.sh
#!/usr/bin/env bash
set -euo pipefail
ENV_NAME=${1:?Usage: $0 <env> <base-url> <api-key>}
BASE_URL=${2:?}
API_KEY=${3:?}
TEMPLATE="lib/core/env/env_ci.dart"
OUT="lib/core/env/env_ci.g.dart"
sed -e "s|<<BASE_URL>>|$BASE_URL|g" \
-e "s|<<API_KEY>>|$API_KEY|g" \
-e "s|<<ENV_NAME>>|$ENV_NAME|g" \
"$TEMPLATE" > "$OUT"
echo "Config generated for $ENV_NAME"
Generated file (in .gitignore): lib/core/env/env_ci.g.dart
Quality Checks Script
Reusable across both CI platforms: scripts/quality_checks.sh
#!/usr/bin/env bash
set -euo pipefail
echo "=== Formatting ==="
dart format --output=none --set-exit-if-changed .
echo "=== Static analysis ==="
flutter analyze --fatal-infos
echo "=== Tests ==="
flutter test --no-pub --coverage
echo "=== Coverage threshold ==="
THRESHOLD=${COVERAGE_THRESHOLD:-70}
if command -v lcov >/dev/null 2>&1; then
COVERAGE=$(lcov --summary coverage/lcov.info 2>&1 | grep 'lines' | awk '{print $2}' | sed 's/%//')
if [ "$(echo "$COVERAGE < $THRESHOLD" | bc)" -eq 1 ]; then
echo "Coverage $COVERAGE% is below threshold $THRESHOLD%"
exit 1
fi
echo "Coverage: $COVERAGE% (threshold: $THRESHOLD%)"
fi
Sentry Symbol Upload Script
For production builds with obfuscation: scripts/upload_symbols.sh
#!/usr/bin/env bash
set -euo pipefail
RELEASE=${1:?Usage: $0 <release-id>}
if ! command -v sentry-cli >/dev/null 2>&1; then
echo "sentry-cli not found, skipping symbol upload"
exit 0
fi
sentry-cli releases new "$RELEASE" || true
sentry-cli upload-dif build/symbols || true
sentry-cli releases finalize "$RELEASE" || true
echo "Symbols uploaded for $RELEASE"
Build Variations by Environment
Dev builds:
flutter build appbundle --release
flutter build ios --release --no-codesign
Staging builds:
flutter build appbundle --release
flutter build ipa --release
Production builds:
flutter build appbundle --release \
--obfuscate \
--split-debug-info=build/symbols
flutter build ipa --release \
--obfuscate \
--split-debug-info=build/symbols
Distribution Channels
| Environment | Android | iOS |
|---|
| Dev | Firebase App Distribution | TestFlight (internal) or none |
| Staging | Firebase App Distribution | TestFlight (external) |
| Production | Google Play Store | App Store Connect |
Required Secrets
Organize secrets into logical groups in your CI platform:
Signing:
ANDROID_KEYSTORE_BASE64 — base64-encoded .jks file
KEYSTORE_PASSWORD — keystore password
KEY_ALIAS — key alias name
KEY_PASSWORD — key password
IOS_CERTIFICATE_BASE64 — base64-encoded .p12 distribution certificate
IOS_CERTIFICATE_PASSWORD — certificate password
IOS_PROVISIONING_PROFILE_BASE64 — base64-encoded .mobileprovision
Distribution:
FIREBASE_TOKEN — from firebase login:ci
FIREBASE_ANDROID_APP_ID — Firebase console app ID
FIREBASE_IOS_APP_ID — Firebase console app ID
FIREBASE_GROUPS — comma-separated tester group names
GOOGLE_PLAY_SERVICE_ACCOUNT_JSON — Play Console service account
APP_STORE_CONNECT_API_KEY_ID — App Store Connect key ID
APP_STORE_CONNECT_API_ISSUER_ID — issuer ID
APP_STORE_CONNECT_API_KEY_CONTENT — .p8 key content
Environment:
STAGING_BASE_URL, STAGING_API_KEY
PROD_BASE_URL, PROD_API_KEY
Monitoring:
SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT
Implementation
After understanding the architecture above, read the reference file for the chosen platform:
- Codemagic:
references/codemagic.md — complete codemagic.yaml with all three workflows
- GitHub Actions:
references/github-actions.md — complete .github/workflows/*.yml files
Both references produce the same outcome: signed artifacts distributed to the right channel per environment.