WhoBuilt

You Don’t Need a Rewrite, You Need React Native Brownfield

May 16, 2025· 49 min· 1.1K views·Watch on YouTube

Speakers

Callstack engineers Oscar Kashnitsky and Burak discuss React Native brownfield integration with host Łukasz on React Universe On Air Coffee Talk #27.

Brownfield keeps the native app in charge

In a greenfield app, React Native typically takes over the app, while a brownfield app adds React Native screens to an actively developed native app. Those screens can sit alongside SwiftUI, UIKit, Kotlin, or Jetpack Compose screens, with React Native initialized when needed, such as when someone opens a Settings tab.

Why the old integration was difficult

Historically, teams copied and modified React Native initialization code, then had to maintain it across React Native versions and architectures. The approach required deep native and React Native knowledge, and Objective-C integration could be awkward in Swift projects. The earlier Brownfield library simplified initialization and view creation for the Old Architecture, but it did not support the New Architecture.

Factories make integration easier to maintain

Oscar describes work that began with React Native VisionOS and led to APIs for creating React Native instances and views. React Native Factory removes the need to subclass RCTAppDelegate, while RCTRootViewFactory handles view creation. The hosts say React Native 0.79 deprecates RCTAppDelegate, with further migration planned for a later release.

Two ways to package React Native

The library provides native-facing APIs for creating React Native views in UIKit, SwiftUI, and Jetpack Compose. Teams can use the standard setup with native and JavaScript code in one repository, or package React Native and its native dependencies as iOS frameworks or XCFrameworks and Android AARs. The packaged approach lets a native app consume React Native without adding CocoaPods or changing its existing repository workflow.

Share data deliberately

The guests recommend limiting data passed between native code and JavaScript because converting types and communicating across the boundary has a cost. Initial props are one simple way to pass data into a screen, and screens in one React Native instance can share JavaScript state. Separate instances can isolate contexts, but add memory, processing, and maintenance overhead.

Takeaways

  • Keep the existing native app and introduce React Native screen by screen instead of planning a full rewrite.
  • Decide whether a shared repository or packaged native frameworks better fits the team's build and review workflows.
  • Use initial props for screen data and keep cross-boundary communication small.
  • Screens in one React Native instance can share JavaScript state; separate instances bring isolation but add overhead.
  • Brownfield integration still calls for native and React Native expertise, even as the APIs improve.

Mentioned in this talk

Search inside this talk

What was claimed 12

Related talks