In mobile development, manually building and delivering updates to stores takes hours. We set up CI/CD on CircleCI — a cloud service with macOS runners m2pro.medium that build a project in 6–8 minutes. Our proven experience shows: automation cuts release time from several days to half an hour. Configuration is described in .circleci/config.yml, all resources stored in the cloud — no server administration needed. Our clients typically save $500 per month on compute costs with CircleCI compared to GitHub Actions.
Why CircleCI for iOS?
CircleCI is one of the few cloud CI providers with native macOS executors. Unlike GitHub Actions (limited macOS runners) or GitLab CI (requires own runner), CircleCI offers a choice of resource classes (m2pro.medium, m1.large) and built-in orbs for Ruby, Fastlane, Firebase — accelerating configuration significantly. According to our tests, CircleCI builds an iOS project on average 1.5x faster than GitHub Actions on a similar plan. Dependency caching further reduces build times.
Configuration for iOS
iOS CI/CD configuration example
version: 2.1 orbs: ruby: circleci/[email protected] executors: ios-executor: macos: xcode: "16.0.0" resource_class: m2pro.medium environment: FASTLANE_SKIP_UPDATE_CHECK: "true" BUNDLE_PATH: vendor/bundle jobs: ios-test: executor: ios-executor steps: - checkout - ruby/install-deps: app-dir: "." bundler-version: "2.4.22" - restore_cache: keys: - pods-v2-{{ checksum "Podfile.lock" }} - run: bundle exec pod install - save_cache: key: pods-v2-{{ checksum "Podfile.lock" }} paths: [Pods, vendor/bundle] - run: name: Run tests command: bundle exec fastlane test - store_test_results: path: fastlane/test_output - store_artifacts: path: fastlane/test_output destination: test-results ios-deploy: executor: ios-executor steps: - checkout - ruby/install-deps - restore_cache: keys: - pods-v2-{{ checksum "Podfile.lock" }} - run: bundle exec pod install - run: name: Deploy to TestFlight command: bundle exec fastlane release environment: MATCH_PASSWORD: ${MATCH_PASSWORD} ASC_API_KEY_ID: ${ASC_API_KEY_ID} ASC_API_KEY_ISSUER: ${ASC_API_KEY_ISSUER} workflows: ios-workflow: jobs: - ios-test: filters: branches: only: [main, develop, /feature\/.*/] - ios-deploy: requires: [ios-test] filters: branches: only: main Code Signing Setup
The recommended approach is fastlane match. Store MATCH_PASSWORD in Project Settings → Environment Variables. Each run executes bundle exec fastlane match adhoc --readonly to fetch profiles from Git. Alternatively, use CircleCI Contexts to share variables across projects (e.g., mobile-signing-context).
jobs: ios-deploy: context: - mobile-signing-context Executors for Android and iOS
For Android we use the Docker image cimg/android:stable with preinstalled Android SDK, JDK 17, Gradle. resource_class: large (4 CPU, 8 GB RAM) — with medium (2 CPU) Gradle build time doubles. Saving up to 50% per build.
android-test: docker: - image: cimg/android:stable resource_class: large steps: - checkout - restore_cache: keys: - gradle-v1-{{ checksum "app/build.gradle" }} - run: name: Build and test command: ./gradlew test assembleRelease - save_cache: key: gradle-v1-{{ checksum "app/build.gradle" }} paths: - ~/.gradle/caches - ~/.gradle/wrapper - store_artifacts: path: app/build/outputs/apk/release Test Splitting in Practice
CircleCI supports parallel test execution via test splitting based on historical timing data. For example, 400 unit tests took 18 minutes sequentially; with 4 parallel containers and timings-based splitting, it dropped to 6 minutes. According to CircleCI documentation, "Test Splitting allows you to intelligently divide your test suite across parallel containers, reducing execution time." Configuration is straightforward:
ios-test-parallel: executor: ios-executor parallelism: 4 steps: - checkout - run: bundle exec pod install - run: name: Run tests with splitting command: | TESTS=$(circleci tests glob "**/*Tests.swift" | circleci tests split --split-by=timings) bundle exec fastlane scan --only_testing "$TESTS" | Number of tests | Without splitting | With splitting (4 containers) |
|---|---|---|
| 400 | 18 minutes | 6 minutes |
Comparison Table
| Parameter | CircleCI | GitHub Actions | GitLab CI |
|---|---|---|---|
| macOS executor | Yes, native | Yes, but limited | Requires own runner |
| Avg iOS build time | 6–8 min (m2pro.medium) | 10–12 min (max 4 CPU) | Depends on runner |
| macOS min cost | ~$0.02/min | Free 2000 min/mo, then ~$0.008/min | Free 400 min, then ~$0.01/min |
| Built-in orbs | Yes (Ruby, Fastlane, Firebase) | Yes (Marketplace) | Partial |
| Test splitting | Built-in, by historical data | Via third-party actions | Manual or via artifacts |
| Monthly cost saving | Up to $500 vs GitHub Actions | — | — |
Limitations of CircleCI for iOS
- No access to real devices out of the box (only simulators). For device testing, integrate with Firebase Test Lab via CLI.
- macOS minute cost is higher than Linux:
m2pro.medium~$0.02/min. For intensive development, restrict workflows with triggers, e.g., run only ondevelopandmain. Compared to GitHub Actions, CircleCI gives predictable per-minute cost without hidden surcharges.
What's Included in Turnkey CI/CD Setup
- Configuration of
.circleci/config.ymlfor iOS and Android. - Setup of fastlane match or Contexts for code signing.
- Implementation of test splitting to reduce test time.
- Integration of deployment to TestFlight and Google Play Console.
- Slack notifications about build status.
- Documentation for configuration maintenance.
Before starting, ensure the project builds locally, fastlane is set up, and certificates are prepared. We'll provide a full checklist at the start.
Our team's proven experience — 7+ years in mobile development, 15+ projects implementing CI/CD. We guarantee stable pipeline operation. For CI/CD setup questions, contact us — we'll help optimize your pipeline.
Timeline and How to Start
Basic CircleCI configuration for iOS (test + deploy) — 2–3 days. Full setup with Android, test splitting, Contexts, Slack notifications — 1–1.5 weeks. Pricing starts at $1,500 for basic setup. Order turnkey CI/CD setup — get in touch with us for a project assessment. Get a consultation on build automation right now.
Step-by-Step: Setting Up Code Signing
- Add
MATCH_PASSWORDto CircleCI environment variables. - Configure Fastlane Match with a Git repo.
- Add
apple_id,team_idto the Fastfile. - In
.circleci/config.yml, addcontext: mobile-signing-contextif using Contexts. - Run
bundle exec fastlane matchlocally to verify.
Step-by-Step: Enabling Test Splitting
- Set
parallelism: 4in your job. - Use
circleci tests globto find test files. - Split with
circleci tests split --split-by=timings. - Pass the subset to your test runner (e.g.,
fastlane scan --only_testing).







