CI/CD Setup for iOS Applications via Bitrise
Bitrise is cloud CI/CD tailored for mobile development. Its key difference from GitHub Actions or GitLab CI: all steps (Steps)—ready-made blocks in Workflow Editor with UI configuration, and most mobile scenarios configure without writing yaml from scratch. For teams without DevOps expertise—this lowers the barrier to entry.
Workflow Editor and Configuration Structure
Bitrise stores configuration in bitrise.yml at repository root. Edit via UI or directly in yaml. Basic iOS workflow:
workflows:
primary:
steps:
- activate-ssh-key: {}
- git-clone: {}
- certificate-and-profile-installer: {}
- cocoapods-install:
inputs:
- is_cache_disabled: "false"
- xcode-test:
inputs:
- scheme: MyApp
- simulator_device: iPhone 15
- xcode-archive:
inputs:
- scheme: MyApp
- distribution_method: ad-hoc
- deploy-to-bitrise-io: {}
- firebase-app-distribution:
inputs:
- app: $FIREBASE_APP_ID
- groups: qa-team
certificate-and-profile-installer—Bitrise-specific Step, downloads certificates from Bitrise Code Signing tab. Upload .p12 and .mobileprovision files via UI or API. Simpler than fastlane match, but means certificate storage on Bitrise servers.
Code Signing Without fastlane match
Bitrise has built-in Code Signing Manager. Upload via Web UI:
- Distribution certificate (.p12 + passphrase)
- Provisioning profile (.mobileprovision)
xcode-archive Step automatically uses uploaded certificates through BITRISE_CERTIFICATE_URL and BITRISE_CERTIFICATE_PASSPHRASE environment variables. Disable Xcode Automatic Signing in xcode-archive:
- xcode-archive:
inputs:
- automatic_code_signing: api-key # or certificate
api-key mode uses App Store Connect API Key (best option—doesn't expire like certificates).
Parallel Workflows and Triggers
Bitrise supports multiple workflows with different triggers:
trigger_map:
- push_branch: main
workflow: deploy
- push_branch: "feature/*"
workflow: test-only
- pull_request_target_branch: main
workflow: pr-check
test-only workflow runs tests only without archiving—saves ~10 minutes on each feature branch push.
Caching
Bitrise uses cache through save-cache / restore-cache Steps:
- restore-cache:
inputs:
- key: "cocoapods-{{ checksum \"Podfile.lock\" }}"
- path: ./Pods
- cocoapods-install: {}
- save-cache:
inputs:
- key: "cocoapods-{{ checksum \"Podfile.lock\" }}"
- path: ./Pods
SPM dependencies cache through ~/Library/Developer/Xcode/DerivedData—can add to path similarly.
Limitations vs Self-Hosted
Bitrise is cloud only. Runners: Xcode 15 (macOS 13), Xcode 16 (macOS 14), etc.—selected in machine type. Fastest—M2 Elite XL (~4 minutes on average project archiving). Cost depends on plan; with active development on 5+ person teams, cloud minutes run out quickly.
For every-commit builds + nightly UI tests on real devices—Bitrise + Device Testing (Firebase Test Lab or own device farm).
Common Setup Issues
- Bundle ID mismatch in provisioning profile and PRODUCT_BUNDLE_IDENTIFIER in xcconfig—xcode-archive fails with No profile for... signed for running on device
- CocoaPods version on Bitrise stack differs from local—add gem install cocoapods --version X.X.X in Script Step
- BITRISE_SCHEME not set—xcode-test uses first available scheme, which may not be correct
Timeline
Basic Bitrise setup (test + archive + TestFlight): 2–4 days. Full configuration with parallel workflows, Device Testing, caching, Slack/Jira integration: 1–1.5 weeks. Cost calculated individually.







