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

entriesplatform-native · verified 2026-08-18 · react-native

Brownfield integration & micro-frontends

reviewedconfidence: lowearly: 2/14 of this tier graded so far (0 overturned) — the public scorecard →

related decisions: ota

cited by: ota

re-verified 5× — 2026-08-18 · 2026-07-28 · 2026-07-16 · 2026-07-10 · 2026-07-06 · changelog

recommendation

A scale-stage concern: embed RN into a native app with react-native-brownfield (+ ReactNativeFactory on iOS). For independently-deployable screens / super-apps, look at Granite or Rock.

  • add RN screens to an existing native app → react-native-brownfield
  • many teams shipping independent bundles → Granite (Toss) / Rock
  • deciding brownfield vs a greenfield rewrite → choose by where the risk sits (continuity vs owning a runtime boundary); a checkpointed greenfield with a real brownfield fallback tests it — see reading

Low confidence — fast-moving or lightly-vetted domain: treat the pick as a vetted lead and prototype before committing.

Options & tradeoffs

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

optiontradeoff
react-native-brownfield (Callstack)embed RN in an existing native app; self-contained iOS init via ReactNativeBrownfield.shared.startReactNative() (wraps RN core's RCTReactNativeFactory)
Brownie (@callstack/brownie)share native↔JS state for brownfield; generates Swift + Kotlin types from .brownie.ts; iOS + Android; stable (v3.13.x, 2026-06)
Granite (Toss)micro-frontend: each screen an independently deployable ~200KB bundle on CDN (ESBuild)
Rock (Callstack)super-apps via micro-frontends + native build caching
Expo brownfield (first-party)SDK 55+: official Expo path for adding Expo/RN to an existing native app (docs.expo.dev/brownfield; `npx brownfield package:ios` XCFramework flow) — the first-party alternative to the Callstack tooling

Verified notes

For embedding RN into native apps or splitting a super-app — a scale-stage concern; mostly Callstack/Toss tooling (several alpha) plus, since SDK 55, a first-party Expo path. CAPABILITY FLIP (2026-07-10, verified vs the Callstack article body): Expo Updates now works in an ISOLATED brownfield architecture with SDK 55 — OTA for embedded RN screens was previously a known limitation ("that limitation is a thing of the past"); see RB-E-OTA. The same prebuilt-XCFramework flow also cuts hybrid iOS compile times ~39% (Callstack, 2026-07). VERSION FLOOR (2026-07-28, verified vs the GitHub release): @callstack/react-native-brownfield 5.0.0 (2026-07-23) has exactly one breaking change — it DROPS Expo SDK 55 support (brownfield-cli bumps to 5.0.0 with it). SDK-55 apps stay on the 4.x line; the SDK-55 capability flip above is therefore a 4.x fact. Pair the brownfield major with the Expo SDK upgrade, not before it.

Canonical reading

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

Migration to React Native in 2026 Starts With a Delivery QuestionMichał Pierzchala (Callstack)

The decision that comes BEFORE this entry's tooling: brownfield or greenfield. The framing is that the trigger for migrating is usually delivery cost (two implementation tracks, two review paths, two QA cycles, two release trains), and that the choice between paths is really a choice of where the risk sits during the transition. Brownfield keeps the native apps as the production host and moves one flow at a time — it preserves installed-app continuity (session state, secure storage, push identity, subscriptions, app extensions) and leaves a native fallback, at the cost of owning a runtime boundary (packaging, host integration, native↔RN navigation, shared state) while maintaining two surfaces at once. Greenfield builds a replacement and ships it under the same bundle ID — less architectural drag and a codebase agents work better in, but continuity becomes the risk: auth, deep links, push tokens, app groups, persisted data and analytics all have to survive the cutover, and mature products fail on accumulated behavior rather than on screens. The third option is the useful one: start greenfield with a fixed checkpoint and a REAL brownfield fallback, where the checkpoint tests product continuity (authenticated flows, analytics, accessibility, performance, at least one meaningful native boundary) and not just how fast screens get rebuilt.

Rebuilding the Doctolib Homepage from Webview to NativeDoctolib

Production case study migrating a 115M-hits/month homepage from WebView to native RN with a BFF-driven section architecture (~50% TTI improvement, measurable conversion gains). Durable brownfield-integration lessons.

Unlocking Expo Updates in an Isolated Brownfield Architecture with SDK 55Callstack

The capability-flip walkthrough behind this entry's note: running EAS/Expo Updates inside an isolated brownfield embed (XCFramework packaging via `npx brownfield package:ios`), which had been a hard limitation of embedded-RN architectures. Read when you need OTA on brownfield screens.

React Native production lessons from React Universe Meetup x ZalandoCallstack

Four hard-won production patterns — brownfield-handoff metrics (Meaningful Render), video-feed jank sequencing, native API bridging, on-device LLM hardware variance. Real-world scale-stage RN guidance.

Sources

Depth (in-domain rules) is owned by the engineering-principles skill — this entry is selection breadth.

The full explanation

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

About brownfield integration & micro-frontends

Diataxis: Explanation. This page builds understanding of the brownfield decision — why embedding React Native in an existing native app is a boundary problem, and how the candidate tools divide that boundary between them. It is not an embedding how-to and not an XCFramework walkthrough. The candidate list and one-line tradeoffs live in the index entry RB-E-BROWNFIELD; depth defers to the engineering-principles skill. Read this for the why.

The one idea that organises everything: the boundary is the product

In a greenfield RN app the framework owns the whole screen and the interesting work is inside it. In a brownfield app the interesting work is the seam: a contract between the host native app and the embedded RN surface. The entry's candidates barely overlap — because each one owns a different clause of that contract:

  • Init. Who starts React Native, and how self-contained that start is. react-native-brownfield's whole pitch is a self-contained iOS init — ReactNativeBrownfield.shared.startReactNative(), wrapping RN core's RCTReactNativeFactory. Expo's first-party path answers the same clause by packaging the embed itself: the npx brownfield package:ios XCFramework flow.
  • State. What crosses the seam while both sides run. Brownie (@callstack/brownie) shares native↔JS state for brownfield and generates Swift + Kotlin types from .brownie.ts — the contract made literal, as generated types on both sides (iOS + Android; stable, v3.13.x, 2026-06).
  • Deployment granularity. How much ships independently. Granite (Toss) makes each screen an independently deployable ~200KB bundle on a CDN (ESBuild); Rock (Callstack) targets super-apps via micro-frontends plus native build caching.
  • Updates. Whether the embedded surface can change without the host shipping. The entry's capability flip (2026-07-10, verified against the Callstack article body): Expo Updates now works in an isolated brownfield architecture with SDK 55 — OTA for embedded RN screens was previously a known limitation, and "that limitation is a thing of the past."

The libraries differ, in other words, by how much of the contract they own: one owns init, one owns the state clause, two own deployment shape, and the Expo path — the first-party alternative to the Callstack tooling, since SDK 55 — owns packaging and, now, updates. (The entry grounds these four clauses; other clauses a real seam has — threading, navigation handoff — it does not cover, though its Zalando reading shows the handoff being measured, via a Meaningful Render metric.)

The default, and why

A scale-stage concern: embed RN into a native app with react-native-brownfield (+ ReactNativeFactory on iOS). For independently-deployable screens / super-apps, look at Granite or Rock.

"Scale-stage" is the load-bearing phrase, and the note repeats it: this is tooling you reach for when a native app — and usually an organisation around it — already exists. The two when-clauses split cleanly along the contract: adding RN screens to an existing native app is the init clause → react-native-brownfield; many teams shipping independent bundles is the deployment clause → Granite / Rock. The landscape is mostly Callstack/Toss tooling (several alpha) plus, since SDK 55, the first-party Expo path.

The landscape, facet by facet

react-native-brownfield (Callstack) — the embed itself: RN inside an existing native app, with the self-contained iOS init (startReactNative() over RCTReactNativeFactory). The recommendation's named default for the add-RN-screens case.

Expo brownfield (first-party, SDK 55+) — the official Expo path for adding Expo/RN to an existing native app (docs.expo.dev/brownfield), built around the npx brownfield package:ios XCFramework flow. Two facts ride on that same prebuilt flow: it is what unlocked Expo Updates in isolated brownfield embeds, and it cuts hybrid iOS compile times ~39% (Callstack, 2026-07).

Brownie (@callstack/brownie) — the state seam: native↔JS state sharing with Swift + Kotlin types generated from .brownie.ts, iOS + Android. Notably carries an explicit stability marker (v3.13.x, 2026-06) in a landscape the note labels "several alpha".

Granite (Toss) — micro-frontends: each screen an independently deployable ~200KB CDN bundle, built with ESBuild.

Rock (Callstack) — super-apps via micro-frontends plus native build caching.

The production evidence lives in the entry's reading list: Doctolib rebuilding a 115M-hits/month homepage from WebView to native RN with a BFF-driven section architecture (~50% TTI improvement, measurable conversion gains), and the Zalando meetup lessons — brownfield-handoff metrics (Meaningful Render), video-feed jank sequencing, native API bridging, on-device LLM hardware variance.

Tradeoffs and failure modes to name out loud

  • Reaching for this at the wrong stage. The entry says it twice — a scale-stage concern. A greenfield app has no host to contract with; this shelf is for apps that already exist.
  • Assuming OTA can't reach embedded screens. Stale since SDK 55: the capability flip is the entry's own headline note, and it points at RB-E-OTA for that side of the story.
  • Treating the landscape as uniformly stable. The note says "several alpha" without naming which; only Brownie carries an explicit stable version and date in the entry. Verify the maturity of any specific tool before committing.
  • Paying full hybrid compile cost. The prebuilt-XCFramework flow exists partly because rebuilding RN inside a native app is expensive — ~39% faster hybrid iOS compiles is the measured win; Rock's native build caching is the same concern at super-app scale.
  • Micro-frontends without the org that needs them. Granite/Rock's when-clause is "many teams shipping independent bundles" — a team-shape condition. One team with one release train is the other when-clause.
  • An unmeasured handoff. The Zalando reading's first lesson is a metric — Meaningful Render — for the brownfield handoff; the seam is a product surface, so it needs its own measurement.

How it interacts with the rest of the stack

  • OTA (RB-E-OTA). The entry's own cross-reference: Expo Updates inside an isolated brownfield embed is the intersection of the two entries — which surface can change without a host release is now a live question on both.
  • Native integration (RB-E-NATIVE). The init clause is built directly on RN core's native surface (RCTReactNativeFactory); the embed sits inside the platform-native layer that entry owns.
  • Depth (engineering-principles). No specialist skill owns brownfield depth here; the defer is to generic architecture and code-quality judgment.

In one paragraph

Embedding React Native in an existing native app makes the boundary the product: a contract between host and embed, whose clauses the candidate tools divide between them. react-native-brownfield owns init (self-contained ReactNativeBrownfield.shared.startReactNative() over RN core's RCTReactNativeFactory); Brownie owns state (native↔JS sharing with Swift + Kotlin types generated from .brownie.ts); Granite and Rock own deployment shape (independently deployable ~200KB CDN bundles per screen; super-apps with native build caching); and Expo's first-party path (SDK 55+) owns packaging via the npx brownfield package:ios XCFramework flow — which also unlocked Expo Updates in isolated brownfield embeds (previously a known limitation; see RB-E-OTA) and cut hybrid iOS compile times ~39%. It is a scale-stage concern in a landscape that is mostly Callstack/Toss tooling, several of them alpha: add RN screens → react-native-brownfield; many teams shipping independent bundles → Granite or Rock; verify maturity before committing.


See also: RB-E-OTA (Expo Updates in isolated brownfield embeds — the entry's capability flip), RB-E-NATIVE (the platform-native surface the init clause builds on). Depth: the engineering-principles skill. Background reading: Doctolib's WebView→native homepage rebuild, Callstack on Expo Updates in isolated brownfield (SDK 55), and the Zalando production lessons (Meaningful Render and friends).

Related in platform-native: native · media · storage · native-ui · keyboard · payments · games · alt-frameworks