Skip to content

CONCEPT Cited by 1 source

React Native as a package

React Native as a package is an architectural pattern for integrating React Native into an existing large native iOS/Android codebase without requiring a full-app rewrite or git-submodule-style coupling. The pattern is named and canonicalised by Zalando's 2025-10 post and generalised by Callstack's open-source package.

The shape

Three parts:

  1. Entry Point — an npm package containing the React Root Component + RN initialisation logic. This is the single unit of truth for the RN side of the integration.
  2. Standalone Developer App — a greenfield RN app that consumes the Entry Point. Gives RN contributors a fast-iteration environment without needing to build the full legacy native app. See concepts/greenfield-developer-app-for-hybrid-engineers.
  3. Native Framework SDK — a native library (iOS + Android) that also consumes the Entry Point, but exposes RN functionality behind a simple native-framework-shaped API (e.g. ReactNativeViewFactory.loadView(...)). This is what the legacy native app links against.
Entry Point (npm)
    ├── Developer App (greenfield RN, fast iteration)
    └── Framework SDK (native wrapper)
            └── Legacy Native App (links SDK like any framework)

Why the pattern exists

Naïve RN brownfield integration fails on three axes — all three are why Zalando moved to this pattern (see concepts/brownfield-rn-integration):

  1. Native-dependency conflicts — RN's native modules or community packages disagree with the main app's versions of the same native deps.
  2. No clear separation — git submodules and similar integration approaches don't isolate RN from legacy code.
  3. Bad developer experience — building the full legacy app just to iterate on RN is slow and requires Xcode/Android Studio expertise, friction-loading web engineers who are expected to contribute.

Packaging RN into an npm module addresses all three:

  • Dep resolution happens in one place (the Entry Point's package.json).
  • Separation is enforced by the package boundary — the legacy app links only the SDK's native surface, not RN source.
  • Developer experience is restored via the Developer App — contributors iterate without building the full native app.

What differs from "normal" RN

A standard RN app has one consumer: the platform launcher (Xcode / Android Studio). The "RN as a package" architecture has two consumers of the same Entry Point, which is the design constraint that shapes everything:

  • The package API must be stable enough to be consumed by two independent codebases.
  • Initialisation must be parameterised (deep-link props, launch options, screen parameters) so different hosts can route into the RN layer.
  • Native interop — wishlist-badge, session state, navigation — must be abstracted behind Turbo Module + DI contracts because the Developer App can't call the legacy app's code and needs to mock those contracts.

Seen in

Last updated · 507 distilled / 1,218 read