skip to content
Andrei Calazans

Exploring Inlined Requires to Improve Cold Start

/ 1 min read

A Hermes CPU profile of our Android app’s cold start had a single block of metroRequire calls running for 2.8 seconds.

Hermes profile showing 2.8s inside importAll → metroRequireImpl → guardedLoadModule during cold start

Every frame in that flamegraph is the same call stack: importAll → metroRequireImpl → guardedLoadModule → loadModuleImplementation. The JS runtime evaluating every require() it encounters — eagerly, synchronously, at startup.

This kicked off three threads of work:

  1. How do inlined requires actually work? The flag is supposed to defer module evaluation. We turned it on and the profile barely moved.
  2. Why didn’t it help? There’s a structural class of modules the transform cannot defer, and we were full of them.
  3. Does Expo Router solve this automatically? File-based routing promises lazy screens by default. We verified the mechanism.

The series: