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-modulesConfigure the platforms
Install pods after adding the packages:
cd ios
bundle exec pod installConfigure the threaded runtime from the app delegate before any secondary runtime is created:
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:
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:
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:
.threaded-runtime/Load the generated entry only inside threaded runtimes:
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:
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.