skills/react-native-best-practices/references/multithreading/SKILL.md
Software Mansion's best practices for multithreading in React Native apps using react-native-worklets. Use when running JavaScript on multiple threads, offloading heavy computation from the JS thread, communicating between runtimes, or sharing data across threads. Trigger on: 'worklet', 'worklets', 'react-native-worklets', 'runOnUI', 'runOnJS', 'scheduleOnUI', 'scheduleOnRN', 'scheduleOnRuntime', 'createWorkletRuntime', 'background thread', 'UI thread', 'worker runtime', 'Serializable', 'Synchronizable', 'multithreading', 'parallel execution', 'offload computation', 'background processing', 'Bundle Mode', or any request to move work off the JS thread in a React Native app.
npx skillsauth add software-mansion-labs/skills multithreadingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Software Mansion's production multithreading patterns for React Native using react-native-worklets.
React Native Worklets lets you run JavaScript code in parallel across multiple threads and runtimes. It powers Reanimated, Gesture Handler, and Skia under the hood.
Before answering any multithreading question, check that react-native-worklets is up to date:
package.json to find the installed react-native-worklets version.npm view react-native-worklets version to get the latest published version.React Native apps have three kinds of runtimes. Picking the right target is the first decision:
What does the work need?
├── Respond to native events or drive animations on the same frame?
│ └── UI Runtime (main thread, one per app)
├── Heavy computation, data processing, or background tasks?
│ └── Worker Runtime (custom thread, many per app)
└── Access React state, navigation, or RN APIs?
└── RN Runtime (JS thread, one per app)
Runtimes do not share memory. Data crosses runtime boundaries through serialization (immutable copies) or Synchronizable (shared mutable state).
Need to run code on a different runtime?
├── Fire-and-forget (no return value needed)?
│ ├── Target is UI Runtime → scheduleOnUI(fn, ...args)
│ ├── Target is RN Runtime → scheduleOnRN(fn, ...args)
│ └── Target is Worker → scheduleOnRuntime(runtime, fn, ...args)
├── Need the return value asynchronously (Promise)?
│ ├── Target is UI Runtime → await runOnUIAsync(fn, ...args)
│ └── Target is Worker → await runOnRuntimeAsync(runtime, fn, ...args)
└── Need the return value synchronously (blocks caller)?
├── Target is UI Runtime → runOnUISync(fn, ...args)
└── Target is Worker → runOnRuntimeSync(runtime, fn, ...args)
The 'worklet' directive: functions that run on Worklet Runtimes must be workletized. Add 'worklet'; as the first statement in the function body. Callbacks passed to scheduleOnUI, scheduleOnRuntime, and similar APIs are autoworkletized by the Babel plugin.
function computeOnUI() {
'worklet';
return 2 + 2;
}
Don't call scheduling APIs from the wrong runtime: scheduleOnUI, runOnUISync, runOnUIAsync, runOnRuntimeSync, runOnRuntimeAsync, scheduleOnRuntime can only be called from the RN Runtime (unless Bundle Mode is enabled). Calling them from a Worklet Runtime throws an error.
Closures are copied, not shared: when a worklet runs on a different runtime, its closure variables are serialized at invocation time. Mutating the original variable after scheduling has no effect on the worklet's copy.
Deprecated APIs: runOnUI is replaced by scheduleOnUI. runOnJS is replaced by scheduleOnRN. runOnRuntime is replaced by scheduleOnRuntime. The new APIs pass arguments directly instead of returning a curried function.
Load at most one reference file per question.
| File | Load when question is about |
|------|------------------------------|
| threading-api.md | Scheduling work across runtimes, creating Worker Runtimes, sync vs async execution, migrating from deprecated APIs |
| shared-memory.md | Passing data between runtimes, closures in worklets, Serializable, Synchronizable, shared mutable state |
| setup-and-advanced.md | Installing worklets, Babel plugin config, Bundle Mode, testing with Jest, feature flags, troubleshooting |
development
Use when the user mentions migrating deep links, switching away from Branch or AppsFlyer, replacing their deep linking SDK, setting up Detour deep linking for the first time, or asks how Branch/AppsFlyer concepts map to Detour. Covers the complete migration end to end - Detour Dashboard configuration, Universal Links and App Links setup, SDK swap with code examples, and analytics migration. Works across Android, iOS, React Native, and Flutter.
development
Complete onboarding guide for developers who are new to Detour, the open-source deferred deep linking SDK by Software Mansion. Use this skill whenever a user asks what Detour is, how to get started with Detour, how to set up deep linking with Detour, how to install the Detour SDK, how to configure the Detour dashboard, or how deferred deep linking works. Also use it when the user has no prior deep linking setup and wants to add deep links to their app. Covers everything from zero to production: account setup, dashboard configuration, Universal Links and App Links, platform SDK integration for React Native, iOS, Android, and Flutter, analytics, and architecture.
tools
React Native / Expo SDK for Fishjam — video/audio streaming on iOS and Android. Use when writing a React Native or Expo app that calls Fishjam, configures the Fishjam Expo plugin, sets up permissions, runs background streaming, integrates CallKit, or renders RTCView. Trigger on: '@fishjam-cloud/react-native-client', 'fishjam expo plugin', 'FishjamProvider mobile', 'useCameraPermissions', 'useMicrophonePermissions', 'useForegroundService', 'useCallKit', 'useCallKitEvent', 'useCallKitService', 'RTCView', 'RTCPIPView', 'ScreenCapturePickerView', 'startPIP', 'stopPIP', 'AudioDeviceType', 'useAudioOutput', '@fishjam-cloud/react-native-webrtc', 'fishjam react native', 'expo fishjam', 'fishjam ios', 'fishjam android', 'broadcast extension'. Re-exports @fishjam-cloud/react-client hooks plus mobile-only: permissions, foreground service, iOS broadcast extension, audio routing, CallKit, Expo config plugin.
tools
Browser-only React SDK for Fishjam — joining rooms, capturing camera/microphone/screen, displaying peers, and acting as a livestream streamer or viewer in a React web app. Use whenever the user is writing a React app in a browser that calls Fishjam APIs, sets up FishjamProvider, or uses any Fishjam React hook. Trigger on: '@fishjam-cloud/react-client', 'FishjamProvider', 'useConnection', 'useCamera', 'useMicrophone', 'useScreenShare', 'usePeers', 'useDataChannel', 'useVAD', 'useLivestreamStreamer', 'useLivestreamViewer', 'useCustomSource', 'useInitializeDevices', 'useUpdatePeerMetadata', 'useSandbox', 'PeerWithTracks', 'joinRoom', 'peerToken', 'fishjamId', 'fishjam react', '@fishjam-cloud/ts-client', 'FishjamClient ts-client'. Covers the provider, the full hook catalog, simulcast configuration, custom sources, data channels, VAD, livestream WHEP playback, device persistence, and reconnection. Briefly notes when to drop down to @fishjam-cloud/ts-client for non-React or worker contexts.