Duolingo Blog

How we sped up Android and iOS builds by 68% on CI

We made our engineers happier by cutting build times down from 50 minutes to 16.

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.

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:

3. Caching is king

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

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


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.