A detailed case study on migrating Expensify's React Native app to NitroFetch, a drop-in fetch() replacement built on Nitro Modules that routes requests through Cronet on Android and URLSession on iOS. Beyond the straightforward global fetch replacement, the integration covered startup prefetching of the critical ReconnectApp request via prefetchOnAppStart, native token-refresh for authenticated prefetches, account-scoped prefetch keys to avoid leaking cached responses across sessions, and reimplementing certificate pinning against Cronet since it doesn't inherit OkHttp or Android Network Security Config pins. Results: average request duration dropped 15-30%, and warm startup P50 improved by 267ms (15.93%) on iOS and 650.5ms (20.18%) on Android.

15m read timeFrom margelo.com
Post cover image
Table of contents
Why NitroFetch?An overview of the migration in ExpensifyInstalling and setting up NitroFetchRegistering prefetching of critical startup requests on the next app startUsing prefetched requests on next app startSetting up prefetching in the native codeBenefits of prefetching over the normal fetchAdding Expensify's authentication to startup prefetchingKeeping Expensify's persisted prefetches account-scopedFeatures specific to ExpensifyHow I tested the final rolloutThe performance resultsWhat I learned

Questions this post answers

How much faster is react-native-nitro-fetch compared to the built-in React Native fetch implementation?

NitroFetch reduced average request duration by roughly 15-30% compared to the built-in React Native networking stack, depending on the request type and network conditions. It routes requests through Cronet on Android and URLSession on iOS while keeping the same fetch() API, so most apps require little to no code change to adopt it. Developers comparing networking stacks for React Native can track benchmarks like this on daily.dev.

Why doesn't certificate pinning work automatically after switching a React Native app's networking to Cronet on Android?

Cronet owns its own TLS stack and does not automatically inherit certificate pins configured through React Native's OkHttp client or Android's Network Security Configuration file. Expensify had to add a custom certificate-pinning implementation plus a NitroFetch patch that applied its public-key pins directly to NitroFetch's Cronet engines, covering ordinary requests, streaming, prefetches, and token refreshes. Teams auditing transport-level security after a networking migration can follow discussions like this on daily.dev.

How much did startup prefetching improve app launch time in Expensify's React Native app?

Warm app start P50 improved from 1,676ms to 1,409ms on iOS, a 267ms (15.93%) reduction, and from 3,223.5ms to 2,573ms on Android, a 650.5ms (20.18%) reduction. This came from using NitroFetch's prefetchOnAppStart to begin the critical ReconnectApp request natively before the JavaScript bundle finished loading, measured over 100 runs each on an iPhone 14 Pro and Samsung Galaxy S10e. Engineers optimizing mobile app startup latency can find measurement approaches like this on daily.dev.

239 Impressions