Comprehensive guide for creating, configuring, and troubleshooting codemagic.yaml files for CI/CD workflows. Use when building mobile apps (Flutter, iOS, Android, React Native) with Codemagic, setting up build pipelines, configuring environment variables, implementing code signing, managing artifacts, or debugging workflow issues.
Scanned 2/12/2026
Install via CLI
openskills install majiayu000/claude-skill-registry---
name: codemagic
description: Comprehensive guide for creating, configuring, and troubleshooting codemagic.yaml files for CI/CD workflows. Use when building mobile apps (Flutter, iOS, Android, React Native) with Codemagic, setting up build pipelines, configuring environment variables, implementing code signing, managing artifacts, or debugging workflow issues.
---
# Codemagic CI/CD Configuration
Configure Codemagic CI/CD workflows using codemagic.yaml for mobile app builds.
## File Location
Place `codemagic.yaml` in the root directory of your repository. Codemagic automatically detects and uses this file for build configuration.
## Core Workflow Structure
Each workflow in codemagic.yaml defines a complete build pipeline:
```yaml
workflows:
workflow-id:
name: Workflow Name
instance_type: mac_mini_m2 # mac_mini_m2, linux, linux_x2, windows_x2
max_build_duration: 60 # minutes (1-120)
environment:
# Environment configuration
triggering:
# Build triggers
scripts:
# Build steps
artifacts:
# Output files
publishing:
# Publishing destinations
```
## Environment Configuration
### Version Management
Specify tool versions in the `environment` section:
```yaml
environment:
flutter: stable # stable, beta, master, or version (e.g., 3.7.6)
xcode: latest # latest, edge, or version (e.g., 14.3)
cocoapods: default # default or version
node: 18.0.0 # version
java: 11 # version
ruby: 2.7.2 # version
```
For Flutter Version Management (FVM), set:
```yaml
environment:
flutter: fvm
```
### Environment Variables
Define variables at three levels with precedence (highest to lowest):
1. **Workflow-specific variables**:
```yaml
environment:
vars:
PUBLIC_VAR: "value"
API_ENDPOINT: "https://api.example.com"
```
2. **Variable groups** (from Codemagic UI):
```yaml
environment:
groups:
- app_store_credentials
- firebase_credentials
- keystore_credentials
```
3. **Built-in variables** - Codemagic exports these automatically:
- `$CM_BUILD_ID` - Unique build identifier
- `$CM_PROJECT_ID` - Project ID
- `$CM_BRANCH` - Git branch name
- `$CM_TAG` - Git tag (if applicable)
- `$CM_COMMIT` - Git commit hash
- `$CM_PULL_REQUEST` - PR number (true/false)
- `$CM_REPO_SLUG` - Repository slug
- `$CM_BUILD_DIR` - Build directory path
- `$CM_ARTIFACT_LINKS` - JSON array of artifact URLs
See [references/built-in-vars.md](references/built-in-vars.md) for complete list.
### Sharing Variables Between Scripts
Variables defined in scripts are scoped to that script only. To share variables, write to `$CM_ENV`:
**macOS/Linux:**
```yaml
scripts:
- name: Set variable
script: |
echo "MY_VAR=value" >> $CM_ENV
- name: Use variable
script: |
echo "Using $MY_VAR"
```
**Windows:**
```yaml
scripts:
- name: Set variable
script: |
Add-Content -Path $env:CM_ENV -Value "MY_VAR=value"
```
### Caching
Cache dependencies to speed up builds:
```yaml
environment:
cache:
cache_paths:
- ~/.gradle/caches
- ~/.pub-cache
- $HOME/Library/Caches/CocoaPods
```
**Important:** Each workflow has its own cache. Caching symlinks is not supported.
## Build Triggers
Define when builds start automatically in the `triggering` section:
```yaml
triggering:
events:
- push # Commits to tracked branches
- pull_request # Pull request opened/updated
- tag # Tag created
- pull_request_labeled # Label added to PR
```
**Note:** Automatic triggering requires webhook configuration in your repository.
### Branch/Tag Patterns
Limit triggers to specific branches or tags:
```yaml
triggering:
events:
- push
branch_patterns:
- pattern: 'main'
include: true
- pattern: 'develop'
include: true
- pattern: 'feature/*'
include: true
- pattern: 'hotfix/*'
include: true
tag_patterns:
- pattern: 'v*.*.*'
include: true
```
### Conditional Triggering
Skip builds based on changed files or custom conditions:
**Changeset filtering:**
```yaml
triggering:
events:
- push
when:
changeset:
includes:
- '.' # All files
excludes:
- '**/*.md' # Skip markdown-only changes
- 'docs/**' # Skip docs changes
```
**Custom conditions:**
```yaml
triggering:
events:
- pull_request
when:
condition: not event.pull_request.draft # Skip draft PRs
```
**Using environment variables:**
```yaml
when:
condition: env.CM_BRANCH == "main"
```
**Complex conditions:**
```yaml
when:
condition: |
env.CM_BRANCH == "main" and
not event.pull_request.draft
```
### Cancel Previous Builds
Automatically cancel outdated builds:
```yaml
triggering:
cancel_previous_builds: true
```
## Scripts
The `scripts` section defines build steps:
### Basic Script Formats
**Single-line:**
```yaml
scripts:
- echo "Hello world"
```
**Named script:**
```yaml
scripts:
- name: Run tests
script: flutter test
```
**Multi-line:**
```yaml
scripts:
- name: Build iOS
script: |
flutter build ios --release
cd ios
xcodebuild -archive
```
**Python/other languages:**
```yaml
scripts:
- |
#!/usr/bin/env python3
import os
print("Running Python script")
```
### Script Options
**Ignore failures:**
```yaml
scripts:
- name: Optional step
script: flutter test
ignore_failure: true # Workflow continues even if this fails
```
**Conditional execution:**
```yaml
scripts:
- name: Deploy to production
script: ./deploy.sh
when:
condition: env.CM_BRANCH == "main"
```
**Changeset-based execution:**
```yaml
scripts:
- name: Build Android
script: ./gradlew assembleRelease
when:
changeset:
includes:
- 'android/**'
```
### Working Directory
Set working directory globally or per-script:
**Workflow-level:**
```yaml
workflows:
my-workflow:
working_directory: packages/my_app
```
**Script-level:**
```yaml
scripts:
- name: Build in subdirectory
working_directory: ios
script: xcodebuild
```
**Important:** Using `cd` between scripts doesn't work because each script runs in a subshell. Use `working_directory` or inline `cd` within a single script.
## Code Signing
See [references/code-signing.md](references/code-signing.md) for complete iOS and Android code signing workflows.
## Artifacts
Specify files to save after the build:
```yaml
artifacts:
- build/ios/ipa/*.ipa
- build/app/outputs/flutter-apk/*.apk
- build/**/*.aab
- $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM
```
Paths can be relative (to clone directory) or absolute. Use glob patterns for flexibility.
## Publishing
Configure where to publish build artifacts:
### Email
```yaml
publishing:
email:
recipients:
- user@example.com
- team@example.com
notify:
success: true
failure: true
```
### Slack
```yaml
publishing:
slack:
channel: '#builds'
notify_on_build_start: true
notify:
success: true
failure: true
```
### App Store Connect
```yaml
publishing:
app_store_connect:
api_key: $APP_STORE_CONNECT_PRIVATE_KEY
key_id: $APP_STORE_CONNECT_KEY_IDENTIFIER
issuer_id: $APP_STORE_CONNECT_ISSUER_ID
submit_to_testflight: true
```
### Google Play
```yaml
publishing:
google_play:
credentials: $GCLOUD_SERVICE_ACCOUNT_CREDENTIALS
track: internal # internal, alpha, beta, production
submit_as_draft: false
```
### Firebase App Distribution
```yaml
publishing:
firebase:
firebase_token: $FIREBASE_TOKEN
android:
app_id: $FIREBASE_ANDROID_APP_ID
groups:
- testers
ios:
app_id: $FIREBASE_IOS_APP_ID
groups:
- testers
```
### Custom Publishing Scripts
```yaml
publishing:
scripts:
- name: Custom deployment
script: |
if [ -f "build/app.ipa" ]; then
./deploy.sh build/app.ipa
fi
```
## Advanced Features
### YAML Anchors for Reusability
Define reusable sections with `&anchor` and reference with `*anchor`:
```yaml
definitions:
instance_mac: &instance_mac
instance_type: mac_mini_m2
max_build_duration: 120
flutter_env: &flutter_env
flutter: stable
xcode: latest
cocoapods: default
setup_script: &setup_script
name: Setup
script: |
flutter pub get
pod install
workflows:
ios-release:
name: iOS Release
<<: *instance_mac
environment:
<<: *flutter_env
scripts:
- *setup_script
- name: Build
script: flutter build ios
android-release:
name: Android Release
instance_type: linux
environment:
<<: *flutter_env
scripts:
- *setup_script
- name: Build
script: flutter build apk
```
### Build Inputs
Allow runtime parameters for flexible builds:
```yaml
workflows:
flexible-build:
name: Flexible Build
build_inputs:
- name: build_flavor
type: choice
description: Select build flavor
required: true
choices:
- dev
- staging
- production
- name: run_tests
type: boolean
description: Run tests before build
default: true
scripts:
- name: Build with flavor
script: |
flutter build apk --flavor $build_flavor
```
### Labels
Add labels for workflow organization:
```yaml
workflows:
my-workflow:
name: My Workflow
labels:
- QA
- ${TENANT_NAME}
- v${APP_VERSION}
```
## Common Patterns
### Flutter Workflow Template
```yaml
workflows:
flutter-workflow:
name: Flutter Build
instance_type: mac_mini_m2
max_build_duration: 60
environment:
flutter: stable
xcode: latest
groups:
- app_store_credentials
vars:
BUNDLE_ID: "com.example.app"
triggering:
events:
- push
branch_patterns:
- pattern: 'main'
include: true
scripts:
- name: Get dependencies
script: flutter pub get
- name: Run tests
script: flutter test
- name: Build iOS
script: flutter build ipa --release
- name: Build Android
script: flutter build apk --release
artifacts:
- build/ios/ipa/*.ipa
- build/app/outputs/flutter-apk/*.apk
publishing:
email:
recipients:
- team@example.com
```
### iOS Native Workflow
See [references/ios-workflow.md](references/ios-workflow.md)
### Android Native Workflow
See [references/android-workflow.md](references/android-workflow.md)
### Monorepo Setup
See [references/monorepo.md](references/monorepo.md)
## Validation and Testing
### Schema Validation
Use JSON schema for IDE validation:
```yaml
# yaml-language-server: $schema=https://codemagic.io/codemagic-schema.json
```
### Local Validation
Check for common issues:
- YAML syntax errors
- Missing required fields
- Invalid instance types
- Incorrect environment variable references
### Debugging
Add debug script to inspect environment:
```yaml
scripts:
- name: Debug environment
script: |
set -ex
printenv
flutter --version
xcodebuild -version
```
## Troubleshooting
**Build not triggering:**
- Verify webhook configuration
- Check branch/tag patterns match
- Review changeset filters
- Ensure codemagic.yaml is in root directory
- Check if [skip ci] is in commit message
**Environment variable not found:**
- Verify variable group names match UI
- Check variable name spelling
- Ensure secret variables are marked as such
- Use `printenv` to list available variables
**Scripts failing:**
- Check exit codes with `set -e`
- Review logs for error messages
- Verify tool versions are correct
- Test scripts locally first
**Code signing issues:**
- Verify certificates are uploaded to Codemagic
- Check provisioning profile validity
- Ensure bundle IDs match
- Review code signing identity references
**Cache not working:**
- Verify cache paths exist
- Check cache size limits
- Ensure paths are not symlinks
- Review cache age (expires after 7 days of inactivity)
## Best Practices
1. **Use variable groups** for sensitive data instead of hardcoding
2. **Enable cancel_previous_builds** to save build minutes
3. **Use changeset filtering** for monorepos to avoid unnecessary builds
4. **Cache dependencies** to speed up builds
5. **Use YAML anchors** to reduce duplication
6. **Add conditional steps** to optimize workflow execution
7. **Test locally** before committing changes
8. **Use semantic versioning** for tags
9. **Keep scripts focused** - one responsibility per script
10. **Document complex workflows** with inline comments
No comments yet. Be the first to comment!