Metro is the default JavaScript bundler shipped with React Native. De Oleza says its goals include sub-second reloads, keeping load times steady as codebases grow, and supporting React Native features such as remote debugging, hot module reloading, and asset generation.
Building JavaScript bundles for React Native
Speaker
Rafael de Oleza, who works on Facebook’s JavaScript Foundation team, explains how Metro builds JavaScript bundles for React Native at a Callstack event.
A bundle contains a runtime, transformed application modules, and startup code. Metro’s runtime registers modules with `__d` and loads them with `__r`, caching exports so modules are evaluated only once. The startup code requires the entry point, which Metro assigns module ID 0.
Metro first creates a dependency graph, then serializes it as a bundle, source map, or another output. Graph generation transforms code with Babel, finds `require` and `import` statements, and resolves dependencies, including platform-specific files such as `Button.android.js` and `Button.ios.js`. Metro handles cycles and repeats this process until it has discovered all dependencies.
De Oleza describes three ways Metro reduces transformation costs: caching, parallel work, and the delta bundler. Facebook’s layered cache includes a remote HTTP cache populated by continuous integration; Jest’s worker package lets Metro transform files across CPUs. During development, the delta bundler tracks changes and sends updated modules instead of rebuilding and sending the whole bundle.
The regular bundle serializer concatenates modules, while the React Native RAM bundle stores them in a binary format with a lookup table. RAM bundles inject the runtime and startup code first, then load modules into the JavaScript virtual machine when required, reducing startup parsing and memory use. Inline requires help preserve lazy loading and can keep dependencies out of production bundles when their surrounding development condition is removed.
Takeaways
- For slow initial builds, consider a remote cache; Metro supports layered caches, including custom HTTP caches.
- For large transformation workloads, parallelize file transforms across CPU cores.
- Use Metro’s delta bundler in development to send changed modules instead of the full bundle.
- Consider RAM bundles with inline requires to reduce startup parsing and memory use.
- Inline requires can help prevent dependencies inside removed development-only code from entering production bundles.
Mentioned in this talk
Search inside this talk
What was claimed 10
- role atRafael de Oleza is works on the JavaScript Foundation team at
Meta
“I work on the JavaScript Foundation team at Facebook.”
YouTube Unverified1 source· Talk
- integrates withMetro integrates with React Native
“Metro is commonly used by React Native.”
YouTube Unverified1 source· Talk
- featureMetro: JavaScript bundler commonly used by React Native
“It's a JavaScript bundler.”
YouTube Unverified1 source· Talk
- metricMetro: Goal of sub-second reload times
“Our goal is to provide sub-second reload times.”
YouTube Unverified1 source· Talk
- uses
“To do so, Metro uses Babel.”
YouTube Unverified1 source· Talk
- usescustom HTTP remote cache at Facebook, populated by a continuous integration job on each master commit
“At Facebook, we have a custom HTTP remote cache.”
YouTube Unverified1 source· Talk
- usesJest's worker package to parallelize file transformations across CPUs
“Metro parallelizes file transformations across CPUs using a package from another awesome project: Jest's worker package.”
YouTube Unverified1 source· Talk
- featureMetro: Delta bundler updates changed graph portions and sends only changed modules during development
“Instead of regenerating the whole graph every time, it can update just the parts that have changed.”
YouTube Unverified1 source· Talk







