Repository navigation
[Due for payment 2026-10-23] [DX] Replace Metro with Re.Pack + a Rust transform pipeline for native builds #100202
Description
Background
Native iOS/Android bundles are built by Metro, which transforms in JavaScript and minifies with single-threaded terser. We ship ~38MB of minified JS. Every engineer bundles several times a day, and CI bundles on every build.
Problem
When an engineer or CI builds the app for iOS/Android, they wait 88-94s for a cold bundle, 11s for every warm rebuild, and 63s for a cold dev server — several times a day, for every engineer.
Solution
Adopt Re.Pack (Rspack-based). We keep the babel path only for the ~23 packages that require it (Flow-typed RN core, native-component registration) and run everything else through fast Rust tools (OXC/SWC) in parallel. Native and web then share the same React Compiler pipeline.
This also reconsolidates us onto the Rust React Compiler. Today we use the babel React Compiler on iOS/Android and the Rust React Compiler on web, and the two have logical differences. After this change, native runs the same OXC loader web already uses.
Results
Same machine, same day, identical code:
- Prod bundle, cold: 88-94s → 54s (~1.7x faster)
- Prod bundle, warm: 11s → 2s (~5.5x faster)
- Dev server, cold: 63s → 47s (25% faster)
- Dev server, warm: 8s → 4s (2x faster)
- Minified JS: 38.1MB → 35.7MB (6.3% smaller)
- Hermes bytecode: 45.1MB → 46.7MB (3.5% larger; known cause with a contained fix to try, and staging
ManualAppStartuptelemetry will show whether it matters)
Verified
Clean boots on iOS simulator, Android emulator, and HybridApp. RN DevTools fully functional. Fast Refresh and dev menu at Metro parity.
Trade-offs
- Re.Pack is a separate bundler, not a fork of Metro, so Metro fixes do not flow into it. When a new RN version ships, things either work as-is or the Re.Pack team adds support. Tracking RN releases is what that team does at Callstack.
- We could miss a future Metro improvement, though the items people actually ask about (tree shaking, code splitting, faster builds, caching) are already in Re.Pack.
- Metro is the default, so libraries get tested against it first and we may hit an edge case. Config takes more work. After a brand-new RN release we may wait for a compatible Re.Pack version.
- Metro stays in the repo and one flag switches back. Our web build already runs on the same engine, so this reduces the number of build systems rather than adding one.
Non-blocking follow-ups
- Switch the babel step to standard
@babel/parser, the parser Metro uses. No perf change expected; it removes a slow-parser edge case for good. - File upstream issues: hermes-parser slowness (repro in hand) and Flow support in OXC.
- Add a small CI check for the babel allowlist. Today, a dependency update that adds a package needing the babel step fails at app launch instead of at build; the check catches it in the PR.
Prior art
A previous attempt at this was tracked in #58311, closed as not planned while blocked on callstack/repack#1153.
Reported in Slack.
Issue Owner
Current Issue Owner: @mallenexpensifyMetadata
Metadata
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
elirangoshen commentedon Sep 7, 2026
Hi, I will be in vacation from tomorrow (08.09) until 15.09
I will find someone from my team to continue to work on this issue while I'm away
kacper-mikolajczak commentedon Sep 8, 2026
Hi 👋 I will be filling in for @elirangoshen here. I am resolving merge conflicts and staying in touch with C+. Let me know if you need anything
elirangoshen commentedon Sep 21, 2026
Hi, I also wanted to add another follow up which I mention in the pr as well
What is your thoughts about it ?
roryabraham commentedon Sep 21, 2026
happy to create another follow-up, but frankly the problem described in that comment isn't clear to me.
collectioneur commentedon Sep 22, 2026
Hey! On an iOS dev build, opening Create expense via the FAB throws
View config not found for component RNCViewPagerand shows "page not found". It's a gap in the Re.PackBABEL_PACKAGESallowlist: packages outside it skip babel codegen, socodegenNativeComponent()runs at runtime and falls back to the legacy path, which has no view config in bridgeless mode.Four packages with codegen specs are missing:
react-native-pager-viewreact-native-gesture-handler@rnmapbox/maps@ua/react-native-airshipI scanned the iOS and Android bundles from the dev server: these four have surviving
codegenNativeComponent( after adding them the count is zero).Anything bundled by Re.Pack is likely affected, so dev builds (
npm run ios/npm run android, standalone and HybridApp) and standalone release bundles. HybridApp release still uses Metro, so production should be fineScreen.Recording.2026-09-22.at.13.22.09.mov
elirangoshen commentedon Sep 22, 2026
Im working on a pr to fix it
elirangoshen commentedon Sep 22, 2026
#101878
45 remaining items
melvin-bot commentedon Oct 16, 2026
@shubham1206agra
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.12-1 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2026-10-23. 🎊
The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]. If no checklist is needed for this issue, you can click: [no checklist button]
melvin-bot commentedon Oct 19, 2026
@shubham1206agra Whoops! This issue is 2 days overdue. Let's get this updated quick!
roryabraham commentedon Oct 20, 2026
@MelvinBot summarize the current status and next steps for this issue.
MelvinBot commentedon Oct 20, 2026
Status: Re.Pack is live for native dev builds and standalone builds. HybridApp release builds still use Metro. Both deploy-blocker fixes are now in production. The HybridApp switch was reopened on Oct 16 and is the main open item.
Done
Next steps
elirangoshen: land the reopened HybridApp Re.Pack switch PR in the submodule, then watch staging for new Android/iOS blockers.shubham1206agra: post the C+ checklist for Match Metro's Android release assets in Re.Pack #102766 before the Oct 23 payment date. This clears the Overdue label.elirangoshen: finish the draft [No QA] Consolidate on the OXC React Compiler and delete the Babel one. It is tracked in [Due for payment 2026-10-07] [DX] Consolidate on the OXC React Compiler and delete the Babel one.elirangoshen: finish the draft [DX] Remove Metro from standalone native builds. A second PR will remove Metro from HybridApp builds once the switch is stable.@babel/parser, file upstream issues, add a CI check for the babel allowlist).Open questions
shubham1206agraaccepted the answer. No follow-up seems needed unless you disagree.view run
melvin-bot commentedon Oct 21, 2026
@shubham1206agra Eep! 4 days overdue now. Issues have feelings too...
melvin-bot commentedon Oct 22, 2026
Triggered auto assignment to @mallenexpensify (
Awaiting Payment)melvin-bot commentedon Oct 22, 2026
Payment Summary
Resolving PRs:
Bundle native builds with Re.Pack + OXC transform pipeline #99407
Add the four missing codegen packages to the Re.Pack babel allowlist #101878
Match Metro's Android release assets in Re.Pack #102766
Contributor: @elirangoshen does not require payment (Contractor)
Reviewer: @shubham1206agra owed $175 via NewDot
Contributor: @kacper-mikolajczak does not require payment (Contractor)
BugZero Checklist (@mallenexpensify)
mallenexpensify commentedon Oct 26, 2026
Payment Summary
Contributor+: @shubham1206agra due $175 via NewDot
I'm assuming the mentions of deploy blockers don't lower the pay, comment/reopen if anyone disagrees.