Business Problem
In 2022, the React Native app had reached the point where the existing Bitrise pipeline was becoming a real delivery cost for the team. A single build could take close to an hour, and with several fixes per day that meant people were waiting for feedback instead of shipping work.
This was not just a matter of "slow CI". Long build times blocked QA, delayed release candidates, and made urgent fixes harder to push through. In practice, even a small hotfix could turn into half a day of coordination because each new Bitrise build was queued behind the previous one.
What I Optimized
I started by breaking down the most expensive steps in the pipeline. It quickly became clear that the workflow was trying to do too much every time:
- it reinstalled JavaScript, Ruby, CocoaPods, and Gradle dependencies from scratch,
- it ran the same full set of steps regardless of whether the goal was PR validation, a QA build, or a release build,
- it used unnecessary clean builds,
- it bundled JavaScript and assets more than once.
Instead of tweaking one step at a time, I redesigned the full flow:
- I split the monolithic workflow into separate paths for pull requests, QA builds, and full releases,
- I added lockfile-based caching for Yarn, Bundler, CocoaPods, and Gradle to avoid repeated cold starts,
- I removed
pod repo updatefrom daily builds and kept deterministicpod install --deployment, - I limited Android builds to the exact required variant instead of building unnecessary flavors on every run,
- I moved JS bundling into one controlled step, removing duplicate bundle generation in release scripts,
- I kept full signing and artifact export only for the workflows that actually needed them.
Technical Decisions
The biggest gain did not come from one magic flag. It came from separating concerns inside the pipeline. Pull request validation, tester builds, and release builds solve different problems and should not pay the same time cost. Before that, all three scenarios were effectively mixed together.
On Android, I used Gradle cache and parallel task execution only for the required variants. On iOS, the key improvement was a stable environment and proper Pods caching so Bitrise did not rebuild the most expensive native dependency layer every time. I also pinned Node, Ruby, and the Xcode stack because small environment drifts had been invalidating cache more often than necessary.
Just as important was what I did not remove: I did not cut critical quality checks. Instead, I separated them from release-only steps and ran them exactly where they provided the most value.
Results
Average build time dropped from around 1 hour to about 15 minutes, a 75% reduction. That changed more than a number in the Bitrise dashboard. It changed how the team could work:
- QA could get test builds the same day without long waiting periods,
- hotfixes stopped being "half-day operations",
- release candidates could be prepared much more frequently and with less coordination overhead.
This case study is a good example of how mobile performance is not only about the app runtime. Sometimes the highest leverage comes from fixing CI/CD so developers and QA stop waiting on the very system that is supposed to speed them up.