Architecture & Performance· 6 min read

How We Cut React Native Startup Time from 3.8s to 1.5s

The levers that cut React Native startup time by about 60%: measuring cold start properly, Hermes, image optimisation and cache-first fetching.

By

Full-Stack, Mobile & AI Engineer

A user taps your icon and waits. At 3.8 seconds the app finally shows something useful, and some of those users have already switched to something else. Startup time is the first impression of every session, and it's measured by stopwatch, not by how elegant the code is.

Across eight apps I migrated to React Native's New Architecture, we cut load time by about 60%, from 3.8 seconds to 1.5, through three levers: Hermes, image optimisation and cache-first fetching. This article explains how to measure React Native startup time honestly, what each of those levers does, and the other changes that usually matter, so you can find your own 60%.

Key takeaways

  • Measure cold start on a mid-range Android phone with a release build. Simulators and debug builds tell you very little.
  • Hermes compiles JavaScript to bytecode ahead of time, so less work happens on launch. It's the default engine, and Hermes V1 has been the default since React Native 0.84.
  • Images are a hidden startup cost: oversized files, no caching and decoding on the main path all delay the first useful screen.
  • Cache-first fetching shows the last known data instantly and refreshes in the background, instead of waiting on the network before rendering.
  • Do less before the first frame: defer analytics, remote config and non-critical requests until after the first screen appears.

Step 0: measure the right thing

"Startup time" means different things, so define it before optimising:

MetricWhat it measures
Cold startApp launched from scratch, process not in memory
Warm startProcess alive, activity or screen recreated
Time to first frameFirst pixels drawn (often the splash screen)
Time to interactiveThe first real screen is usable with data

The number users feel is cold start to interactive. Measure it on a release build, on a mid-range Android device (where the gap is biggest), several times, and take the median.

Tools that help:

  • React Native DevTools for JavaScript profiling.
  • Android Studio profiler and Perfetto, and Xcode Instruments' App Launch template, for native startup.
  • Performance marks in your code (performance.now() at key moments) logged in release builds.
  • Production metrics: Android vitals in Play Console treats cold starts of 5 seconds or more as excessive, and Expo's EAS Observe reports cold and warm launch, time to render and time to interactive from real devices.

Lever 1: Hermes and less JavaScript work at launch

Hermes compiles your JavaScript into bytecode when you build the app, so the device doesn't parse and compile it at runtime. React Native has defaulted to Hermes for years, and Hermes V1 became the default engine in React Native 0.84.

Being on Hermes is the start, not the end. What matters is how much JavaScript runs before your first screen:

  • Inline requires (a Metro option, enabled in React Native's default Metro config) delay loading modules until they're actually used.
  • Avoid heavy work at module scope, such as building large lookup tables, initialising SDKs or parsing big JSON files when files are imported.
  • Trim dependencies. Large date, utility or charting libraries imported on the first screen add parse and execution time.
  • Lazy-load screens that aren't needed at launch.

With the New Architecture, native modules are also initialised lazily as TurboModules when first used, rather than all at startup, which removes work you never asked for.

Lever 2: images

Images are easy to overlook because they "load asynchronously". But the first screen often waits for a hero image, a logo or a list of thumbnails, and oversized images cost network time, memory and decode time.

  • Serve the right size. Don't send a 3000-pixel photo to a 400-pixel slot. Resize on the server or through an image CDN.
  • Use modern formats such as WebP or AVIF where supported.
  • Use a caching image component like expo-image, with disk and memory caching, and placeholders (for example a blurhash) so layout is stable.
  • Prefetch images for the first screen during the splash, and don't block rendering on them.
  • Bundle the few images needed at launch (logo, empty states) instead of fetching them.

Lever 3: cache-first fetching

The slowest startup pattern is: open app, show spinner, wait for the network, then render. On a train or a weak signal, that's seconds.

Cache-first flips it:

  1. On launch, render immediately from the last cached data.
  2. Fetch fresh data in the background.
  3. Update the screen when it arrives, without a jarring reload.

With TanStack Query, persist the query cache to fast local storage (MMKV is a common choice) and restore it at startup. Users see their dashboard, workouts or bookings instantly, and the app quietly refreshes. This is the same approach behind offline-first apps, applied to startup.

From the field: These three levers come straight from my own work: migrating eight apps to the New Architecture and cutting load time by about 60% (3.8 seconds to 1.5) through Hermes, image optimisation and cache-first fetching, while holding stable 60fps animation. None of it required leaving React Native.

Other changes that usually help

SymptomLikely causeFix
Long splash screenWaiting for fonts, auth, remote config in sequenceLoad in parallel; keep the splash only for essentials
Spinner after the splashNetwork-first first screenCache-first rendering
Slow only on AndroidLow-end CPU, big JS bundle, large imagesProfile on a mid-range device; trim and resize
Startup got slower over monthsSDKs initialised at launchDefer analytics and non-critical SDKs until after first frame
Janky first scrollHeavy list items, unoptimised imagesFlashList, smaller images, memoised rows

Keep the splash screen visible only until the essentials are ready (SplashScreen.preventAutoHideAsync() and hideAsync() in Expo), and render the first real screen as soon as you can, even if some data is still loading.

FAQ

What is a good startup time for a React Native app?

Aim for well under two seconds to a usable screen on a mid-range Android phone with a release build. Google's Android vitals treats cold starts of five seconds or more as excessive. Users notice anything that feels slower than the apps they use every day.

Does Hermes make React Native apps start faster?

Yes. Hermes compiles JavaScript to bytecode at build time, which reduces work on launch, and it's the default engine; Hermes V1 has been the default since React Native 0.84. The remaining gains come from running less JavaScript before the first screen.

How do I measure React Native startup time?

Measure cold start to interactive on a release build on a real mid-range device, several times, and use the median. Combine native profilers (Android Studio, Perfetto, Xcode Instruments), performance marks in your code, and production metrics such as Android vitals or EAS Observe.

Does the New Architecture improve startup time?

It can. TurboModules are initialised lazily when first used, instead of all at launch, and JSI removes bridge overhead. The biggest improvements still come from doing less work before the first screen: lighter JavaScript, smaller images and cache-first data.

Next steps

If your app takes more than a couple of seconds to become usable, I can profile it on real devices and give you a prioritised list of fixes, usually with the biggest wins in the first week. Get in touch, or see how I work as a React Native developer.

Sources

Bhuwanesh Sisodia

Bhuwanesh Sisodia

Full-Stack, Mobile & AI Engineer

Bhuwanesh Sisodia is a Full-Stack, Mobile & AI Engineer based in Mumbai, with 7+ years of experience and 50+ apps shipped to the App Store and Google Play. He works independently with startups and product teams worldwide.

About meGitHubLinkedInX

Related