Back to Journal
Mobile/Frontend

Mobile CI/CD Pipelines Best Practices for Startup Teams

Battle-tested best practices for Mobile CI/CD Pipelines tailored to Startup teams, including anti-patterns to avoid and a ready-to-use checklist.

Muneer Puthiya Purayil 14 min read

Startups building mobile apps need CI/CD pipelines that balance speed with reliability on a minimal budget. You likely have 1-3 mobile developers, no dedicated DevOps engineer, and need to ship weekly. These practices get you from manual builds to automated releases without over-engineering.

Choosing Your CI Platform

For startups, cloud-hosted CI is the right default. Self-hosted macOS runners make sense at 50+ builds/day; most startups run 5-15.

PlatformiOS SupportFree TierCost at Scale
GitHub ActionsmacOS runners2,000 min/month$0.08/min macOS
BitriseNative mobile90 min/week$90/month
CircleCImacOS runnersLimited$0.08/min macOS
CodemagicNative mobile500 min/month$95/month

Codemagic or Bitrise are purpose-built for mobile and reduce setup time. GitHub Actions is more flexible but requires more configuration.

Minimal Fastlane Setup

ruby
1# fastlane/Fastfile
2default_platform(:ios)
3 
4platform :ios do
5 desc "Run tests"
6 lane :test do
7 scan(
8 scheme: "App",
9 devices: ["iPhone 15"],
10 clean: true,
11 )
12 end
13 
14 desc "Build and push to TestFlight"
15 lane :beta do
16 match(type: "appstore", readonly: true)
17 
18 increment_build_number(
19 build_number: latest_testflight_build_number + 1,
20 )
21 
22 build_app(
23 scheme: "App",
24 export_method: "app-store",
25 )
26 
27 upload_to_testflight(
28 api_key: app_store_connect_api_key,
29 skip_waiting_for_build_processing: true,
30 )
31 end
32end
33 
34platform :android do
35 desc "Run tests"
36 lane :test do
37 gradle(task: "test", project_dir: "android/")
38 end
39 
40 desc "Build and upload to Play Store internal"
41 lane :beta do
42 gradle(
43 task: "bundle",
44 build_type: "Release",
45 project_dir: "android/",
46 )
47 
48 upload_to_play_store(
49 track: "internal",
50 aab: "android/app/build/outputs/bundle/release/app-release.aab",
51 json_key: ENV["PLAY_STORE_JSON_KEY"],
52 )
53 end
54end
55 

This is the minimum viable Fastlane configuration. It handles the two tasks that consume the most developer time: running tests and pushing builds to testers.

Code Signing for Startups

iOS: Fastlane Match

bash
1# One-time setup
2fastlane match init
3# Creates a private Git repo for certificates
4 
5fastlane match appstore
6# Generates and stores App Store certificates
7 
ruby
1# Matchfile
2git_url("[email protected]:yourcompany/certificates.git")
3storage_mode("git")
4type("appstore")
5app_identifier("com.yourcompany.app")
6 

Match eliminates code signing headaches permanently. The initial setup takes 30 minutes. Without it, you'll spend 30 minutes debugging signing issues every few weeks.

Android: Keystore Management

bash
1# Generate release keystore (one-time)
2keytool -genkeypair \
3 -v \
4 -storetype PKCS12 \
5 -keystore release-keystore.jks \
6 -alias release \
7 -keyalg RSA \
8 -keysize 2048 \
9 -validity 10000
10 

Store the keystore in a secure location (1Password, AWS Secrets Manager) and inject it into CI via environment variables. Never commit keystores to Git.

GitHub Actions Workflow

yaml
1name: Mobile CI/CD
2on:
3 pull_request:
4 branches: [main]
5 push:
6 branches: [main]
7 
8jobs:
9 test-ios:
10 runs-on: macos-latest
11 steps:
12 - uses: actions/checkout@v4
13 
14 - uses: ruby/setup-ruby@v1
15 with:
16 ruby-version: '3.2'
17 bundler-cache: true
18 
19 - name: Install pods
20 run: cd ios && pod install
21 
22 - name: Run tests
23 run: bundle exec fastlane ios test
24 
25 test-android:
26 runs-on: ubuntu-latest
27 steps:
28 - uses: actions/checkout@v4
29 
30 - uses: actions/setup-java@v4
31 with:
32 distribution: 'temurin'
33 java-version: '17'
34 
35 - name: Run tests
36 run: cd android && ./gradlew test
37 
38 deploy-beta:
39 if: github.ref == 'refs/heads/main' && github.event_name == 'push'
40 needs: [test-ios, test-android]
41 runs-on: macos-latest
42 steps:
43 - uses: actions/checkout@v4
44 
45 - uses: ruby/setup-ruby@v1
46 with:
47 ruby-version: '3.2'
48 bundler-cache: true
49 
50 - name: Deploy iOS beta
51 env:
52 MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
53 MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_AUTH }}
54 APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.ASC_KEY_ID }}
55 APP_STORE_CONNECT_API_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
56 APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.ASC_KEY_CONTENT }}
57 run: bundle exec fastlane ios beta
58 
59 - name: Deploy Android beta
60 env:
61 PLAY_STORE_JSON_KEY: ${{ secrets.PLAY_STORE_JSON_KEY }}
62 run: bundle exec fastlane android beta
63 

This workflow runs tests on every PR and deploys to TestFlight/Play Store on every merge to main. Total CI cost for a startup running 10-15 builds/day: approximately $100-200/month on GitHub Actions.

Need a second opinion on your mobile/frontend architecture?

I run free 30-minute strategy calls for engineering teams tackling this exact problem.

Book a Free Call

React Native / Expo Specifics

yaml
1# For Expo managed workflow
2deploy-ios:
3 runs-on: ubuntu-latest # EAS Build runs in the cloud
4 steps:
5 - uses: actions/checkout@v4
6 - uses: actions/setup-node@v4
7 with:
8 node-version: 20
9 
10 - name: Install dependencies
11 run: npm ci
12 
13 - name: Run tests
14 run: npm test
15 
16 - name: Build and submit
17 run: npx eas-cli build --platform ios --profile production --auto-submit
18 env:
19 EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
20 

Expo's EAS Build handles code signing, builds, and app store submission from a single command. For React Native startups, this eliminates 80% of CI/CD configuration. The cost is $15/month for the EAS subscription.

Over-the-Air Updates

typescript
1// For React Native with Expo Updates
2import * as Updates from "expo-updates";
3 
4async function checkForUpdates(): Promise<void> {
5 try {
6 const update = await Updates.checkForUpdateAsync();
7 if (update.isAvailable) {
8 await Updates.fetchUpdateAsync();
9 await Updates.reloadAsync();
10 }
11 } catch (error) {
12 console.log("Update check failed:", error);
13 }
14}
15 

OTA updates bypass app store review for JavaScript and asset changes. This is a significant advantage for startups that need to ship bug fixes same-day rather than waiting 24-48 hours for App Store review.

Anti-Patterns to Avoid

Manual builds from developer machines. A single developer laptop shouldn't be the only machine that can produce a release build. When that developer is on vacation, releases stop. Automate from day one.

Testing only on simulators. Simulators miss real-device issues: camera integration, push notifications, background processing, and performance on lower-end devices. Run critical path tests on at least one real device via a device farm.

No beta testing phase. Shipping directly to production without beta testing is reckless. TestFlight and Play Store internal tracks exist for a reason — use them for at least 48 hours before each production release.

Complex branching strategies. Startups don't need GitFlow. Trunk-based development with short-lived feature branches and automatic beta deployment on merge to main is simpler and faster.

Ignoring build caching. Without CocoaPods cache, derived data cache, and Gradle cache, builds take 2-3x longer. A 15-minute build on every PR drains CI minutes budget fast.

Production Checklist

  • Automated tests running on every PR
  • Fastlane Match for iOS code signing
  • Automatic beta deployment on merge to main
  • TestFlight + Play Store internal track for beta testing
  • Build caching (CocoaPods, Gradle, derived data)
  • App Store Connect API key (not personal credentials)
  • Play Store service account JSON key
  • Slack/Discord notification on build success/failure
  • Version number auto-increment
  • Environment configuration (dev/staging/production API URLs)

Conclusion

A startup mobile CI/CD pipeline should take one engineer one day to set up and require minimal ongoing maintenance. Fastlane handles the complexity of code signing and app store uploads; GitHub Actions (or Codemagic/Bitrise) provides the execution environment. The total cost is $100-300/month — trivial compared to the engineering time saved on every release.

Resist the temptation to build a sophisticated release pipeline before you need it. Automatic beta deployment on merge to main covers 90% of startup needs. Add staged rollouts, feature flags, and multi-track testing when your user base and team size justify the complexity.

FAQ

Need expert help?

Building with mobile/frontend?

I help teams ship production-grade systems. From architecture review to hands-on builds.

Muneer Puthiya Purayil

SaaS Architect & AI Systems Engineer. 10+ years shipping production infrastructure across fintech, automotive, e-commerce, and healthcare.

Engage

Start a
Conversation.

For teams building at scale: SaaS platforms, agentic AI systems, and enterprise mobile infrastructure. Scope and fit are evaluated before any engagement begins.

Limited availability · Q3 / Q4 2026