react-brain
Browse decisions
React & language foundations 3App architecture 9UI 12Platform & native 9Build, test, observe, secure 6AI in React apps 3stack composerdecision recordscensusstaleness bencharchitecturechangelogmethodologyroadmap

entriestooling-ops · verified 2026-07-13 · react + react-native

Build tooling, bundlers & monorepo

reviewedconfidence: hightrack: heldthis tier holds 75% on the public scorecard (6/11 graded · 0 overturned) →

related decisions: p2p

cited by: react-core · dx

re-verified 4× — 2026-07-13 · 2026-07-10 · 2026-07-09 · 2026-07-06 · changelog

recommendation

Web: Vite 8 (Rolldown). React Native: Metro (+ Hermes V1, precompiled iOS binaries). Monorepo: pnpm workspaces + Turborepo. Expo for managed velocity.

  • RN bundler alternative for module federation / super-apps → Re.Pack 5 (worth the complexity when independent teams need independent JS release cadences within one app — Callstack's own criterion)
  • want the Rolldown/Rollup plugin ecosystem on RN (experimental) → Rollipop — early alpha, prototype only, not an Expo path
  • slow RN CI → prebuilt binaries (RNRepo) and/or Rock build caching
  • Babel is the Metro bottleneck → react-native-swc (SWC) or facetpack (OXC; early — pin + keep the Babel fallback)
  • Pear app → esbuild-bundle to dist (desktop) or Metro + bare-pack for the Bare worker (mobile), not the web/Metro defaults — see RB-E-P2P
  • new web project → Vite; legacy web → webpack/Rspack

Options & tradeoffs

the field considered — and why each one isn’t the default here

optiontradeoffevidence
MetroRN bundler2.7M/wk · ships in 10/34
Vite 8 / Rspack 2 / webpackweb bundlers; Vite 8 defaults to the Rust Rolldown bundler; Rspack 2 adds RSC + 2.1 ships the Rust React Compiler via its built-in SWC loader (7–13x the Babel plugin); Vite default for new web129.8M/wk · ships in 9/34
Turborepo / Nx + pnpm/yarn workspacesmonorepo task graph + caching
Expo vs bare RNmanaged velocity vs native control
react-native-swcRust/SWC Metro transform — faster than Babel; custom Babel plugins need SWC equivalents (e.g. worklets plugin for Reanimated)
facetpack (early)@ecrindigital/facetpack — Rust/OXC Metro transformer (claims ~36x Babel transforms), one-line metro.config, Babel fallback for Flow packages, Doctor CLI; v0.2 (2026-01), early-stage85/wk
RNRepo (Software Mansion)prebuilt native binaries via Maven; cuts CI build time (~50% reported)
Re.Pack 5 (Rspack)Metro alternative on Rust-based Rspack; module federation / super-apps
Rock (Callstack)native build-artifact caching (reported 35min → <4min); works with Metro or Re.Pack
Rollipop (early alpha)Metro replacement powered by Rolldown (the Vite team's Rust bundler) — inherits the Rollup/Rolldown plugin ecosystem, Yarn PnP by default, dev dashboard; bare RN CLI only (no Expo); early-alpha, not production
Vite+ (beta)VoidZero's unified toolchain — one entry point over Vite, Vitest, Rolldown, tsdown, Oxlint, Oxfmt; MIT; framework-agnostic; BETA (2026-07) — 'stable, but not yet complete', migration command may need manual follow-up129.8M/wk · ships in 9/34

evidence: npm weekly downloads (signals snapshot) · “ships in n/D” = adoption across the production-app census, honest denominators

npm weekly downloads (from the corpus's last signals run): vite 129.8M · esbuild 252.8M · @react-native/metro-config 2.7M · metro 10.3M · webpack 41.3M · @ecrindigital/facetpack 85

Verified notes

ENGINE + BUILD (verified vs RN 0.84 blog): Hermes V1 is the DEFAULT JS engine since RN 0.84 (2026-02-11; experimental opt-in from 0.82, also opt-in in Expo SDK 55) — automatic if already on Hermes. RN 0.84 also ships PRECOMPILED iOS binaries by default (fetched at pod install, faster builds) and raised the minimum to Node 22.11+. RN is on a bi-monthly release cadence. Prebuilt native libraries (RN 0.83 artefacts, RNRepo) are the broader trend. BUNDLERS: Metro stays the RN default (RN 0.79 added ~3x faster cold start); Expo SDK 56 extends the trend with prebuilt XCFrameworks for its most complex modules (~16% faster median clean iOS builds, verified vs the SDK 56 changelog); Re.Pack 5 (on Rspack) is the main alternative, and Rollipop (leegeunhyeok/rollipop, early alpha per its repo) now brings Rolldown — the same Rust bundler behind Vite 8 — directly to the RN side; remote-JS Chrome debugging was removed in RN 0.79 (use RN DevTools). Rollipop verified vs its repo 2026-06-30 (early-alpha, not production). WEB TOOLCHAIN: a Rust wave — Vite 8 on Rolldown (1.0; ~10–30x Rollup), the Oxc family (Oxlint/Oxfmt), Bun; Cloudflare acquired VoidZero (Vite/Vitest/Rolldown/Oxc) — tools stay MIT. Vite+ BETA (2026-07-02, verified vs the VoidZero announcement; 2nd signal after TWiR #289's watch flag): the consolidation made product — one CLI over the whole VoidZero stack, MIT, framework-agnostic; beta, so watch rather than migrate existing multi-tool setups yet. Adversarially stress-tested 2026-06-25 (SURVIVES, high): Vite 8 shipped stable (2026-03) with Rolldown GA as the default; the Rust React-Compiler napi pullback affects only that compiler's JS path, not Rolldown-as-bundler; Metro stays the RN default. UPDATE 2026-07-06: the Rust React Compiler has since merged into SWC and ships in Rspack 2.1 (7–13x the Babel version, verified vs the Rspack 2.1 blog) — Rolldown's pullback is a Rolldown-integration choice, not a dead Rust port.

Canonical reading

Editorial annotations on why each piece matters — the articles themselves are the originals; read them there.

Rust Is Eating JavaScriptLee Robinson

The first-principles explainer for WHY the JS toolchain is going Rust — memory safety, no GC, real parallelism, the redundant-parsing problem — mapping the whole landscape (esbuild, SWC, Oxc/Biome, Rspack, Rolldown). Durable cross-cutting context, not a single release.

Vite 8.0 is out!The Vite / VoidZero team

Why maintaining two pipelines (esbuild + Rollup) was unsustainable and how Rolldown unifies dev/prod on one Rust bundler (10-30x faster), with Oxc semantic analysis driving better tree-shaking. The primary source for the Vite+Rolldown+Oxc consolidation.

Exploring Inlined Requires: how they really workAndrei Calazans

Exactly what Metro's inlineRequires Babel transform does, why React/RN stay hoisted, why default imports aren't inlined, and how rnx-kit's esbuild path differs (real tree-shaking vs startup-only). The canonical Metro startup-mechanics reference.

The Complete Guide to React Native Build OptimizationThe Mythical Engineer

Why RN Android builds are slow (conservative Gradle/Metro/C++ defaults) and how parallel Gradle, dynamic Metro workers, ccache, and single-architecture builds cut times from 20+ min to 2-5 min, with benchmarks. The RN-CI build-perf dimension the other readings here don't cover.

Watching

Curated talks, podcasts & videos — the A/V companion to the reading list.

How React Native Builds Actually Work (APK, AAB, IPA, APP)Code with Beto

Walkthrough of what actually happens between `npx expo run` and an installable artifact — the Gradle/Xcode stages behind APK/AAB/IPA and where Metro's bundle lands in them. The A/V companion to this entry's build-pipeline facts. (Verified via YouTube oEmbed: title + author.)

Sources

The full explanation

The reviewed long-form essay behind this entry — the why, not a how-to. Also on GitHub.

About build tooling, bundlers & monorepos (React & React Native)

Diataxis: Explanation. This page builds understanding of the build/bundler decision — the reasoning behind the pick. It is not a tutorial: the candidate list and one-line tradeoffs live in the index entry RB-E-BUILD; the feedback-loop side (CI, lint, hooks) is RB-E-DX. Read this for the why.

Two toolchains, one trend

The first thing to get straight: web and React Native have separate build toolchains, and they're moving at different speeds.

  • Web is in the middle of a churn — the "bundler wars" — that is now resolving toward Rust. Vite 8 ships on Rolldown (a Rust bundler), unifying what used to be two pipelines (esbuild for dev, Rollup for prod). The broader wave is the same: SWC, the Oxc family (Oxlint/Oxfmt), Bun, Rspack — all Rust/native, all chasing speed. Cloudflare acquiring VoidZero (Vite/Vitest/Rolldown/Oxc) signals this consolidation; the tools stay MIT.
  • React Native is steadier: Metro remains the default bundler, and the action is in the native build (Gradle/Xcode) and the JS engine, not in swapping bundlers.

The durable trend across both is Rust is eating the toolchain — not as fashion, but because native code without a GC buys real, compounding build-speed wins. That's the lens for reading any specific tool choice.

The default, and why

Web: Vite 8 (Rolldown). React Native: Metro (+ Hermes V1, precompiled iOS binaries). Monorepo: pnpm workspaces + Turborepo. Expo for managed velocity.

On the web, Vite is the default for new projects — fast dev server, and now a unified Rust production bundler. On React Native, Metro stays the default not by inertia but because it's tightly integrated with RN's resolution, Hermes, and the New Architecture's codegen; RN 0.79 already gave it ~3× faster cold start. The engine question is settled too: Hermes V1 is the default JS engine since RN 0.84, which also shipped precompiled iOS binaries (faster pod install builds) and raised the floor to Node 22.11+ (verified against the RN 0.84 blog). For monorepos, pnpm workspaces + Turborepo give a cached, parallel task graph. And Expo is the managed-velocity choice — it owns a large slice of the build/release pipeline so you don't have to.

The landscape, and when each one wins

Metro — the RN default; integrated, Hermes-aware, New-Arch-codegen-aware. You don't replace it casually. RN-side build speed problems are better solved by caching and transforms than by swapping the bundler (below).

Vite 8 / Rspack 2 / webpack (web) — Vite (on Rolldown) is the new-project default; Rspack (Rust) is the webpack-compatible high-performance path and adds RSC support; webpack remains for legacy. The selection axis is greenfield-vs-legacy and how much you value Vite's DX.

Re.Pack 5 (Rspack) — the main Metro alternative for RN, on Rust-based Rspack; reach for it specifically for module federation / super-apps, not as a general Metro replacement.

react-native-swc — a Rust/SWC Metro transform, faster than Babel; the answer when Babel is the Metro bottleneck (note: custom Babel plugins need SWC equivalents — e.g. the worklets plugin for Reanimated).

RNRepo / Rock (native build caching) — RN's slowest step is usually the native build, not the JS bundle. RNRepo (prebuilt native binaries via Maven) and Rock (native build- artifact caching) attack that directly — the lever for slow RN CI, with large reported wins.

Turborepo / Nx + pnpm/yarn workspaces — monorepo task graph + caching; the standard way to make many-package repos build incrementally.

Expo vs bare RN — managed velocity vs native control. Expo owns more of the toolchain (builds, updates, config); bare gives full control at the cost of owning it yourself.

Tradeoffs and failure modes to name out loud

  • Swapping Metro to "go fast." RN's bottleneck is usually the native build or Babel, not Metro itself. Reach for native build caching (Rock/RNRepo) or react-native-swc before replacing the bundler; replace Metro (Re.Pack) for module federation, not for raw speed.
  • Chasing the newest Rust tool mid-project. The web toolchain is consolidating fast; rewriting a working build to the bundler-of-the-month is churn. New project → Vite; existing working build → migrate only on a concrete pain.
  • Letting Babel rot the RN build. If the Metro transform is the bottleneck, that's a fixable, measurable problem (react-native-swc) — but mind the custom-plugin parity gap.
  • Confusing build with DX. The bundler is one piece; the feedback loop (CI gates, lint, hooks) is what keeps the build honest — that's RB-E-DX, not this entry.

How it interacts with the rest of the stack

  • Native (RB-E-NATIVE). Codegen, precompiled iOS binaries, and Hermes V1 are the build- time face of the New Architecture; this entry and that one describe the same machine from the build and the runtime side.
  • DX (RB-E-DX). Monorepo task running, CI, and lint/format live there; the bundler choice feeds into that loop.
  • RN versions (RB-E-RN-VERSIONS). Hermes-V1-default, precompiled iOS, and the Node-22.11 floor are version-pinned facts; verify a specific row against the RN blog.
  • React core (RB-E-REACT-CORE). The React Compiler plugs into the build (Babel/SWC/Oxc/ Vite); your bundler choice determines how you enable it.

In one paragraph

Treat web and RN as two toolchains with one shared trend — Rust is eating the build for speed. On the web, default to Vite 8 (Rolldown) and only migrate a working build for a real reason. On React Native, keep Metro (with Hermes V1 default and precompiled iOS since RN 0.84), and fix slowness where it actually is — native build caching (Rock/RNRepo) or an SWC transform — rather than swapping the bundler (Re.Pack is for module federation, not raw speed). Use pnpm + Turborepo for monorepos and Expo for managed velocity, and keep the feedback-loop concerns in RB-E-DX.


See also: RB-E-NATIVE (codegen / Hermes / precompiled iOS), RB-E-DX (CI, lint, monorepo task running), RB-E-RN-VERSIONS (Hermes-V1 / Node-floor facts), RB-E-REACT-CORE (the Compiler's build plugin).

Related in tooling-ops: testing · dx · observability · security · ota