DEV Community

Viktor Benei
Viktor Benei

Posted on • Originally published at bitrise.io

How Build Cache for React Native works: caching the C++ your CI keeps recompiling

React Native projects compile twice. There's the platform layer you think about - Kotlin/Java on Android, Swift/Objective-C on iOS - and underneath it a shared C++ foundation: Hermes, Folly, ReactCommon, the turbo modules. On CI, that C++ gets recompiled from scratch on every single build.

You don't feel it locally because your incremental builds reuse the previous output. But CI starts from a clean clone every time, so it pays the full C++ compilation cost on every run.

Why Gradle and Xcode caching don't save you here

Both Gradle and Xcode ship their own caching. The problem is what they don't cover. The React Native Android plugin declares its C++ compilation tasks as non-cacheable, so Gradle's build cache skips right over them - every clean clone re-compiles every translation unit from scratch.

So you can have Gradle caching fully dialed in and still watch minutes disappear into clang on every CI run.

What actually caches C++: ccache with remote storage

The tool for the job is ccache - but with a twist. A local ccache directory dies with your CI runner. To get real value you need remote storage so a cache entry produced by one build is available to the next build on a different machine.

On Android you point CMake at ccache:

CMAKE_CXX_COMPILER_LAUNCHER=ccache
Enter fullscreen mode Exit fullscreen mode

The hard part is getting ccache to speak to a remote backend reliably. In our case we bridged ccache's wire protocol to a gRPC storage backend with a small Go process that ccache talks to over a Unix socket, translating remote read/write requests in real time.

Bringing it together

A full RN pipeline ends up with three caching systems working in concert:

  1. Gradle build cache for JVM compilation
  2. Xcode's LLVM Content Addressable Storage for Apple platforms
  3. ccache + remote storage for the C++ layer

On Bitrise this is one command - bitrise-build-cache activate react-native - which installs ccache and sets the environment up for you, then you monitor hit rates in Insights. But the mechanics above apply to any RN CI setup.

Does it actually move the needle?

From private beta teams:

  • An iOS team: 9m 35s → 5m 28s (~43% faster)
  • A multi-platform team: Android ~17m → ~9m (~46%), iOS ~10m 50s → ~6m 30s (~40%)

Read the full writeup

The full post goes deeper into the storage-helper design and the setup - How Build Cache for React Native works: caching the C++ your CI keeps recompiling.


Full disclosure: I work at Bitrise. The C++/ccache mechanics here apply to any React Native CI setup, not just ours.

Top comments (0)