How do React Native's interop layers let a library written for the old architecture run on the New Architecture, and what can they not provide?
answer
- two layers: modules and views
- legacy modules behind NativeModules
- legacy view managers wrapped for Fabric
- no custom shadow nodes, no concurrency
- no match renders Unimplemented component
basics
~20 sInterop layers adapt old-architecture code: legacy native modules are served through NativeModules and legacy view managers are hosted in a Fabric wrapper. They cannot provide custom shadow nodes, concurrent features, synchronous typed calls or codegen type safety.
solid answer
~50 sThere are two interop layers. On the **module** side, a legacy native module with no codegen spec is still registered, and JavaScript reaches it through `NativeModules`, which in the bridgeless runtime is backed by a native proxy. On the **view** side, when Fabric meets a component name it has no Fabric implementation for, it falls back to wrapping the legacy view manager in an interop component (on iOS, `RCTLegacyViewManagerInteropComponentView`); if even that fails, iOS renders a placeholder reading `Unimplemented component: <Name>`. What interop cannot provide: access to **custom shadow nodes**, **concurrent features** on that surface, and the benefits of migrated modules (**synchronous calls, shared C++, codegen type safety**). Paper-only APIs such as `UIManager.createView` also just log an error. Interop buys time; React Native says it will stay for the foreseeable future but eventually be removed.
go deeper
Know that React Native can still run many older libraries on the New Architecture through interop layers, one for native modules and one for native components.
Explain how each layer works: legacy modules served through NativeModules, legacy view managers wrapped inside a Fabric component, and the Unimplemented component placeholder when nothing matches.
Name what interop cannot do: custom shadow nodes, concurrent features, synchronous typed calls, Paper-only UIManager calls, bridge access, and read each symptom to its cause.
Treat interop as temporary credit: rank interop-only dependencies by business risk and plan their migration before React Native removes the layer.
## Why interop exists When the New Architecture became React Native's default in 0.76, thousands of libraries were written against the old one: **native modules** built on the bridge and **native components** built as view managers for the old renderer, Paper. Requiring all of them to migrate first would have blocked every app. So React Native shipped **interop layers**: adapters that let old-style code run inside the new runtime without changes. Since 0.82 the New Architecture is mandatory, so for an unmigrated library the interop layer is the only way it runs at all. ## The module side A legacy module is a class written the old way, for example extending `ReactContextBaseJavaModule` with `@ReactMethod` methods on Android, or using `RCT_EXPORT_MODULE` on iOS, with no **codegen spec** describing its API in TypeScript. - The New Architecture's module system, **Turbo Native Modules**, normally loads modules generated from a spec. Its interop path also accepts these legacy classes; on Android it finds the `@ReactMethod`-annotated methods by reflection. - JavaScript reaches such a module through **`NativeModules`**. In the bridgeless runtime, `NativeModules` is backed by a native proxy object rather than a bridge message queue. - Migrated modules are instead loaded with `TurboModuleRegistry.getEnforcing` against a typed spec, which is how new modules should be written. ## The view side Fabric looks a component name up in a fixed order. On iOS the order is: 1. a component view class registered for that name in Fabric; 2. a class supplied by the app's third-party Fabric components provider; 3. the **legacy view manager interop**: the old view manager wrapped in `RCTLegacyViewManagerInteropComponentView`, which forwards props and commands to it; 4. otherwise, an **unimplemented view** that renders the text `Unimplemented component: <Name>`. On Android the equivalent Fabric interop is enabled by default. The placeholder is a useful clue: it means the name matched nothing at all, typically because the native code is not linked or the view manager is not registered, not merely that the library is old. ## What interop cannot give you | Missing capability | Why it matters | |---|---| | Access to **custom shadow nodes** | Components that compute their own layout natively cannot do it through interop | | **Concurrent features** on that surface | A legacy component cannot take part in transitions and other concurrent rendering | | **Synchronous, typed module calls** | Legacy modules miss codegen type safety, synchronous methods and shared C++ | | **Paper-only APIs** | Calls such as `UIManager.createView`, `updateView`, `manageChildren` or `setJSResponder` log "is not available in the new React Native architecture" and do nothing | | **Full bridge access** | On iOS a legacy module's `bridge` is a proxy; methods such as `delegate` return nil and log that they are unsupported | Those limits come from React Native's own guidance: without migrating native modules you do not get shared C++, synchronous calls or codegen type safety, and without migrating native components you cannot use concurrent features. ## How long interop will last - The 0.76 announcement says a future release will remove the interop layer and modules will then need to support the New Architecture. - The 0.82 post says the interop layers stay in the codebase **for the foreseeable future**. - The 0.84 post, which compiled legacy iOS code out, states that the interop code needed for compatibility remains. So interop is a bridge across a migration, not a destination. A library that only works through it is a library with a known expiry. ## Practical reading - **Works through interop and has no custom layout**: usually fine today; track the library's migration. - **Renders `Unimplemented component`**: check installation and linking first. - **Logs Paper-only API errors**: the library calls APIs interop does not cover; it needs an update, a replacement or a port. - **A legacy module is missing from `NativeModules`**: interop only adapts modules that are present in the native build, so check installation and autolinking before suspecting the architecture. - **Works, but the team wants synchronous calls or concurrent rendering on that screen**: that is the signal to migrate the module or component rather than to tune the interop path. ## Summary Interop adapts legacy modules through `NativeModules` and legacy views through a Fabric wrapper, so most old libraries keep running. It does not add the New Architecture's advantages to them, it does not cover every old API, and React Native intends to remove it one day.
- On iOS, a screen shows 'Unimplemented component: <MapMarkerView>'. What does that tell you?Fabric found neither a Fabric component nor a legacy view manager with that name, so it fell back to the placeholder. That usually means the native code is missing from the build: the library is not installed or linked, pods were not reinstalled, or the view manager is not registered. An old library that is linked correctly would normally render through the legacy view manager interop instead.
- Why can't a legacy component that renders fine through interop use concurrent features?React Native's guidance is explicit: without migrating a native component to the Fabric Native Component API, you cannot use concurrent features on it. The interop wrapper forwards props and commands to an old view manager, but that view manager was not built for Fabric's model, so the surface stays limited until the component is migrated.
Interop is a travel adapter: your old plug fits the new socket and the device powers on, but it will never charge faster than the adapter allows, and the day the hotel stops lending adapters you need a new charger.
saying these in an interview costs you the question
- Legacy modules still talk to JavaScript over the old asynchronous bridge
- Interop gives an old library every benefit of the New Architecture
- An 'Unimplemented component' placeholder means the library is merely too old
- Interop layers were removed together with legacy iOS code in 0.84
- Paper-only UIManager methods such as createView keep working through interop