React Native Runtimes
Get started

Installation

Install the runtime and shared-state packages and configure iOS, Android, and Metro.

Install the two runtime packages plus react-native-nitro-modules (a peer dependency for both):

npm install @react-native-runtimes/core @react-native-runtimes/state react-native-nitro-modules

Configure the platforms

Install pods after adding the packages:

cd ios
bundle exec pod install

Configure the threaded runtime from the app delegate before any secondary runtime is created:

AppDelegate.swift
import NativeComposeThreadedRuntime

ThreadedRuntime.configure(
  withReactNativeDelegate: delegate,
  launchOptions: launchOptions
)

If you want a runtime ready at startup, prewarm it from Swift:

ThreadedRuntime.prewarmRuntime("conversation-inbox-runtime")

When to prewarm from native

Native prewarm is the fastest way to be ready when the first surface mounts — use it for any runtime that the user is likely to see in the first navigation. Everything else can be prewarmed from JS effects.

See iOS setup for the full reference.

Add the Nitro and shared-state packages so threaded runtimes can find them. These are not part of the generated host package list, so you must register them yourself:

MainApplication.kt
import com.nativecompose.threadedruntime.ThreadedRuntime
import com.nativecompose.threadedzustand.ThreadedZustandPackage
import com.margelo.nitro.NitroModulesPackage

class MainApplication : Application(), ReactApplication {
  override fun onCreate() {
    super.onCreate()

    ThreadedRuntime.setExtraReactPackagesProvider {
      listOf(
        NitroModulesPackage(),
        ThreadedZustandPackage(),
      )
    }

    loadReactNative(this)
  }
}

Prewarm a named runtime from Kotlin when useful:

ThreadedRuntime.prewarmRuntime(
  applicationContext,
  "conversation-inbox-runtime",
)

If a long-lived background business runtime should expose the same native modules as the main app runtime, provide the app's package list and prewarm it as a business runtime:

import com.facebook.react.PackageList
import com.nativecompose.threadedruntime.ThreadedRuntime

ThreadedRuntime.setMainReactPackagesProvider {
  PackageList(this).packages
}

ThreadedRuntime.prewarmBusinessRuntime(applicationContext, "background")

See Android setup for the full reference.

Wrap your Metro config so the package can generate the threaded entry file:

metro.config.js
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const { withThreadedRuntime } = require('@react-native-runtimes/core/metro');

const config = {};

module.exports = withThreadedRuntime(
  mergeConfig(getDefaultConfig(__dirname), config),
  {
    roots: ['App.tsx', 'src'],
    generatedDir: '.threaded-runtime',
    generatedEntry: 'entry.js',
  },
);

Add the generated folder to .gitignore:

.gitignore
.threaded-runtime/

Load the generated entry only inside threaded runtimes:

index.js
if (global.__THREADED_RUNTIME_ENV__ || global._is_it_a_list_env === true) {
  require('./.threaded-runtime/entry');
}

The generated entry registers lazy component loaders and the ThreadedRuntimeHost root used by native.

Tip: per-runtime startup code

For startup code that should only run on a specific runtime, create a root-level file named index.<runtime>.ts — for example index.background.ts. The generated entry emits a static conditional require for it and matches <runtime> against global.__THREADED_RUNTIME_ENV__.kind and .runtimeName.

See Metro setup for the full plugin options.

Verify the install

Render the simplest possible threaded surface:

App.tsx
import { OnRuntime } from '@react-native-runtimes/core';
import { Text, View } from 'react-native';

function Hello() {
  return (
    <View>
      <Text>Hello from a second JS runtime!</Text>
    </View>
  );
}

export default function App() {
  return (
    <OnRuntime name="hello-runtime">
      <Hello />
    </OnRuntime>
  );
}

Rebuild the app. If you see the text, the runtime, the Metro plugin, and the native side are all wired up correctly.

Next

Read Rendering components on a background runtime to learn the full OnRuntime / ThreadedScreen / threadedComponent API.

On this page