We validate our code changes as part of continuous integration (CI) and have checks like tests and linters before and after a developer merges their code onto the main branch. We call them pre-merge and post-merge checks on CI.

Imagine waiting over 50 minutes for every pre- and post-merge check on your code. Sounds painful, right? Now imagine running through this grind several hundred times a week. That was our reality until we, the Test and Release Infrastructure (TRI) team, decided enough was enough.

Fast forward to today: those 50-minute waits? Gone. Android and iOS pre- or post-merge times now clock in at under 16 minutes. To iteratively get to the 16-minute mark, we measured the time to build the app on CI, a.k.a, build time, and made specific changes to bring this down. Build time is relevant because we built the app from scratch (without cached artifacts) every time there was a code change to run tests or linters.   

Here’s the inside scoop on how we made this magic happen—and yes, it involved some fun experimentation and a bit of sweat (but thankfully, no tears).


What worked (a.k.a., our secret sauce)

1. Newer, shinier machines

Let’s face it: the old AWS instance types running our builds were like trying to watch high-definition videos on a dial-up connection. Upgrading them was an obvious first step.

  • For Android: We tested 16 instance types and learned the hard way that throwing more CPU power at a JVM doesn’t help—it’s a memory hog! The r7a instances, with their ample memory and reliable availability, turned out to be perfect. Result? A 21% improvement in CI build times.Oh, and pro tip: Fast disk I/O (like NVMe SSDs) speeds up Android builds even more. That’s next on our to-do list.
  • For iOS: Apple Silicon M2 Macs are much more efficient than the old x86-based mac1.metal instances. By switching to EC2 mac2-m2.metal machines, we slashed build times by a whopping 60% on CI. Developers were able to notice the improvement here immediately.

And yes, we made peace with slightly higher costs. Newer machines are pricier, but quicker builds made them worth every penny.

2. More parallelization, less bottleneck drama

CI pipelines are like crowded intersections. Too much happening in one place? Total traffic jam. We revamped our pipelines to keep tasks moving smoothly:

  • For Android: We rearranged and optimized tasks, reducing serial execution time by 20% on CI. This was key to balancing our spending on those shiny new machines.
  • For iOS: We killed long startup delays by ditching Jenkins Pipelines for freestyle jobs. Startup times shrank, and our developers got their builds faster. (Bonus: we built a nifty Python library to maintain some of the syntactic sugar we loved from Pipelines!)

3. Caching is king

Why reinvent the wheel—or, in this case, rebuild unchanged code?

  • Dependency Caching: Cached dependencies meant fewer downloads and less network latency. For iOS, we leveraged  SwiftPM’s built-in caching, shaving ~4 minutes off of CI build times.
  • Task Caching: For Android, we tapped into Gradle’s remote S3 cache. This avoided redundant compilations and reused outputs whenever possible. Result? 25% faster builds on CI.

4. Toolchain upgrades (a.k.a., spring cleaning)

Sometimes, all you need is an upgrade. We waved goodbye to KAPT (Kotlin annotation processing) and embraced KSP, which is faster and sleeker. Along with a Kotlin bump, this cut Android CI build times by another 30%.


What didn’t work (but was worth a try)

XCRemoteCache woes

We had high hopes for XCRemoteCache, a tool for iOS remote caching. But after months of head-scratching over cache misses and mysterious build failures, we had to call it quits. Lesson learned? Not every tool fits every setup. Bazel is next on our radar.


Results: the glow-up in numbers and sentiments

A chart detailing the decreasing build times over four iterations.
Praise from our engineers.

Key takeaways (i.e., what we learned)

  1. Small Wins Matter: Even shaving a few seconds off CI times makes a big difference over hundreds of PRs. Developers notice—and appreciate—these changes.
  2. Speed + Stability = Happy Developers: Slow, glitchy builds can derail productivity. Fixing outliers and adding retry logic kept things smooth, fast, and frustration-free.
  3. Reduce Waste, Responsibly: New machines meant higher costs, but smarter resource allocation (hello, Savings Plan and EC2 Autoscaling Groups!) kept things in check.


The bottom line

Improving build times isn’t just about better CI—it’s about creating a better developer experience. And when your developers are happy, everyone wins. The 16-minute runs help with shipping feature changes more seamlessly, and we continue to amplify the experience through faster/automated code reviews, approvals, and merge/deployment processes on the DevX AI team.