Product Updates

Make React Native builds 4x faster with fingerprint-based caching on Bitrise

Fingerprinting isn't a new idea.‍

Build tools have relied on it for years to avoid redoing work that hasn't changed. In React Native CI it's still a bit of a secret sauce: a fingerprint-based caching technique that can make your builds several times faster, yet one that surprisingly few teams have switched on. The premise is simple: most of the time you're only changing JavaScript, so most of the native modules are reusable. Expo's recent Best CI/CD for mobile apps in 2026 shows fingerprint-based caching taking an iOS build from roughly 10–15 minutes down to about 2 minutes for a JS-only change. The good news: you don't need anything exotic to get there, just a way to fingerprint the inputs and a cache to store the output. Here is the flow:

  1. Fingerprint the native inputs: hash package.json, your lockfile, app.json, native lockfiles.
  2. Cache restore by that key. A hit means the last build's native output is valid.
  3. Reuse or rebuild. On a cache hit, reuse the app and just refresh the JavaScript inside it. Otherwise, do the full native build once and cache it.
Flowchart of a fingerprint-based cache workflow on Bitrise. Native inputs feed a fingerprint step, then restore-cache checks for a hit. A cache miss runs a full native build and saves the signed app, around 3.5 minutes. A cache hit rebuilds only the JS bundle and re-signs the app, around 44 seconds.
Measured on expo-build-fingerprint-demo: a JS-only change went from ~3.5 min to ~44 s (about 4.8x faster).

Fingerprint caching with restore-cache and save-cache

On Bitrise you can wire it up yourself with a bit of scripting. Bitrise's key-value cache (restore-cache / save-cache) ships with the platform. A tiny open-source step turns your input files into a cache key, and the rest is a few lines of YAML:

- react-native-fingerprint@0:
    inputs:
      - path_list: |-
          package.json
          package-lock.json
          app.json
      - key_prefix: build-fingerprint
- restore-cache@3:
    inputs:
      - key: $BUNDLE_HASH_STRING

On a hit you restore the prebuilt, signed app and only refresh the JavaScript inside it. For Android that means swapping assets/index.android.bundle in the APK and re-signing; for iOS it's the same move with the JS bundle inside a cached .xcarchive (or the simulator .app). Either way, the slow native build stays cached and is skipped on the next JS-only commit.

Build Cache for React Native: cache compiler outputs, not just the app

The DIY approach is powerful and free. You design the fingerprint, wire the run_if conditions, and do a little IPA/APK surgery (Hermes, assets, re-signing). To make it even better, Bitrise Build Cache for React Native gives you an extra boost for speeding up the compilation of native modules with almost no setup.

Setup is a single activate step, with no cache keys or cache objects to manage. Where the DIY approach reuses a finished app, Build Cache goes a level deeper and caches compiler outputs (Gradle tasks, Xcode via an LLVM-CAS-backed cache, C++ via ccache), so even a dependency change rebuilds only what actually changed. You also get cache hit rates, time saved, and build analytics out of the box, and the same remote cache speeds up builds on developer machines, not just CI.

DIY fingerprint cache Bitrise Build Cache for React Native
Setup
A step + a script you own
Wrap your build command
What it caches
The finished signed app
Compiler outputs (Gradle, Xcode, C++)
Dependency change
Full rebuild
Only changed parts recompile
Extras
None
Observability, insights, shared local cache
Cost
Included
Managed add-on (free trial)

Results: a JS-only change builds 4x faster

The open-source expo-build-fingerprint-demo runs all of this on Bitrise. Here is that app built for iOS three ways, on the same g2.mac.large machine:

Approach When it runs Native build Total build
Normal native build
Dependency / native change
1m 47s
2m 50s
Bitrise Build Cache with full native build
Dependency / native change
1m 10s
2m 05s
Fingerprint with cache hit
Only JavaScript changed
Skipped (12s bundle swap)
50s


From the results a few things stand out:

  • If it is a JS-only change, skip the native build: The fingerprint hit avoids the Xcode compile entirely; a 12-second bundle swap instead of a ~1m 47s native build.
  • A genuine rebuild with Bitrise Build Cache support. When a dependency actually changed, the DIY skip can't help (the fingerprint moved), but Build Cache reduced the Xcode build time, ~2 min down to ~1 min, with a single activate step in the workflow.

They're complementary: fingerprint reuse wins the JS-only case, Build Cache wins the genuine-rebuild case. The same app's Android build shows the same pattern, a JS-only change drops from ~3.5 min to ~44 s.

Numbers are from the demo app on g2.mac.large; the Build Cache run uses the Xcode 26 stack it requires, so treat them as indicative rather than a lab-controlled A/B.

The bigger the app, the bigger the payoff

‍This demo is tiny, so a JS-only change saves roughly two minutes. But the swap time stays essentially flat (you're only re-bundling JavaScript), while the native build it replaces grows with your project. Real apps with dozens of native modules often take 10–20 minutes to compile (Expo's own post cites 10–15 minute iOS builds), so the same fast path can turn a 15-minute build into under a minute. Multiply that across every JS-only build your team runs in a week and the savings turn into hours of reclaimed CI time. The ROI scales with your app and your team.

Faster React Native builds on any CI

Fast React Native CI comes down to one habit: fingerprint your inputs and reuse what didn't change. It's a simple technique, and a surprisingly well-kept one, and on Bitrise you can wire it up yourself in a few lines of YAML. From our experiments it’s about 4x faster on a JS-only change. And because the whole trick is a fingerprint plus a bundle swap, it works on whatever CI you run, Expo or bare React Native, with no lock-in to a single build service. When you'd rather not maintain that plumbing and want observability plus faster dependency-change builds too, Bitrise Build Cache for React Native is the way to go. Ultimately, your builds get faster and you keep the choice.

Kick the tires: clone the demo, connect it to Bitrise, run once, then change only App.tsx and watch the second run fly. If you’d rather not maintain the scripts yourself, start a Build Cache for React Native trial.

contents

Get started for free

Get a 30-day free trial and join the 400,000+ mobile developers who already love Bitrise.

Start free trial

More from the blog