Library / SDK
margelo/react-native-worklets-core avatar
margelo/react-native-worklets-core

react-native-worklets-core: moving JavaScript onto another thread in React Native

๐Ÿงต A library to run JS functions ("Worklets") on separate Threads

792 stars66 forksC++MIT

At a glance

What is it?
A C++ backed React Native library that turns a marked JavaScript function into a worklet running on a separate thread. It is less a standalone feature and more a peer dependency for native modules, and the top-level documentation leaves real adoption questions unanswered.
Who is it for?
react-native-worklets-core fits one narrow case: a React Native app that owns native C++ code and needs a JavaScript callback to run on another thread, where it makes more sense to depend on it as a peer dependency of a module such as react-native-wishlist than to add it directly. Teams without native code of their own, and teams whose heaviest JavaScript is animation, should look at the runtime already shipped with their app before installing it.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Worklets take heavy JavaScript off the React Native UI thread

react-native-worklets-core is a library for running JavaScript functions on separate threads inside a React Native app. The project calls itself a Worklet runner, and the sample function in its README is short enough to read in one breath:

js
const worklet = () => {
  'worklet'
  return Math.random()
}

The randomness is incidental. What matters is the 'worklet' directive at the top of the function body, which tells the toolchain that this function is allowed to leave the JavaScript thread that normally drives the interface. The README states the goal plainly: running JS functions on separate Threads.

The people this helps are mobile engineers whose app performs real computation in JavaScript, a frame of animation, an image transform, a burst of parsing. On React Native the JavaScript thread is shared, so a long synchronous loop on it shows up as a dropped frame. Relocating that loop to another thread takes it out of that queue.

The project also positions itself as infrastructure rather than a feature. A note in the README says that in most cases react-native-worklets-core should not be used as a standalone dependency but rather as a peer dependency for other modules such as react-native-vision-camera, react-native-wishlist, or react-native-skia. If you are neither building nor using such a module, this library is probably not the thing to reach for.

A 'worklet' directive and a Babel plugin decide what moves

The mechanism is a build-time plugin, not a scheduling call made from application code. The installation steps place an entry named react-native-worklets-core/plugin into the plugins list of babel.config.js. The plugin recognises the 'worklet' marker in a function body and compiles that function so it can be shipped to a native thread, where the C++ portion of the library takes over.

The repository layout matches that division of labour. The tree carries a cpp/ directory, ios/ and android/ directories, a react-native-worklets-core.podspec, a plugin.js entry point, and a src/ directory, and the primary language is C++. The JavaScript side marks the work and hands it across a native boundary; it does not implement the scheduler itself.

Nothing visible in the package manifest exposes a thread pool size, a queue policy, or a way to name a thread. Those details, if they exist, live in the C++ sources rather than in the published files list, which names src, lib, android, ios, cpp and the podspec. A reviewer cannot size threads or predict scheduling from what the npm package advertises.

Three installation steps, and the third one clears the Metro cache

The setup is three numbered steps, and the order matters. The package comes from npm through Yarn, the Babel plugin is registered, then Metro is restarted from a clean cache so the bundle is rebuilt with the plugin active.

sh
yarn add react-native-worklets-core

The plugin goes into the plugins array in babel.config.js:

js
module.exports = {
  plugins: [
    ["react-native-worklets-core/plugin"],
    // ...
  ],
  // ...
};

And the bundler is restarted with the cache dropped:

sh
yarn start --reset-cache

That last step is the one most likely to be skipped, and it is not cosmetic. A bundle compiled before the plugin was registered has nothing to interpret the 'worklet' directive, so the marker would remain an ordinary string in the function body and the code would quietly stay on the JavaScript thread. The README lists the reset as its own numbered step rather than folding it into the install command.

The usage section itself is a pointer, not a tutorial. The Usage heading in the README contains one line, a link to USAGE.md, and the project description links to docs/WORKLETS.md for the definition of a Worklet. Those two documents are where the call API lives.

The library expects to sit underneath other packages, not on top of them

The README's most pointed statement is about positioning rather than features. It says react-native-worklets-core should in most cases not be used as a standalone dependency but rather as a peer dependency for other modules such as react-native-vision-camera, react-native-wishlist, or react-native-skia.

The credits section explains why the architecture looks the way it does. The concept of Worklets was introduced by Software Mansion in Reanimated v2, and this library is inspired by Reanimated v2 with a few structural changes to the Worklets architecture, made to suit different use cases such as integrating it with other C++ libraries. The initial version was built by Christian Falch, according to the same credits list.

That is the entire pitch in two sentences. If your feature is a piece of native code that needs a JavaScript callback to run in the background, this library lets you write that callback in JavaScript and have it execute elsewhere. If your feature is an ordinary React Native component, a native worklet runner adds a Babel plugin and two native builds to your app for no benefit, which is precisely why the README frames the library as a peer dependency.

The evaluation path leads to files the README does not describe

Adoption decisions here are harder than they should be, because the entry points for real usage are stubs and the failure paths are undocumented. The package manifest lists the files that ship with the library, including src, lib, android, ios and cpp, and it names no native dependency beyond the podspec. The repository does ship an example/ directory containing its own android and ios projects, a metro.config.js and a src folder, which is where a reviewer could look for a working call site, but the README never points a reader there.

The consequence is specific. The scheduling API, the shape of the handle returned to JavaScript, and the behaviour of a worklet that throws are not visible from the top-level documentation. Neither is what happens when a worklet is cancelled or when a captured object is too large to copy across the thread boundary. For a library whose entire job is moving code across a native boundary, those are the questions that should decide adoption, and none of them are answered by the pages a new user is pointed to first.

The scripts in package.json show what the maintainers run on themselves: jest for tests, tsc --noEmit for type checking, eslint over the JavaScript and TypeScript sources, and a bob build step that runs before packing. That gives some confidence about the package shape, but not about the runtime semantics of a failing worklet.

How this differs from the worklet model inside Reanimated

The natural alternative is the worklet model that Software Mansion built into Reanimated v2, and the difference is stated in the credits rather than left open. Worklets in Reanimated exist to drive animations on the UI thread and are tied to that animation runtime. This library keeps the idea of a marked worklet but changes the structure so that the worklet can be integrated with other C++ libraries.

That difference only pays off when you genuinely have a C++ library to integrate. For a team whose heaviest JavaScript is an animation, the animation runtime already shipped with the app covers the case and adds no separate native module. For a team building a camera frame processor or a native-backed list, the peer dependency arrangement described in the README is the reason this project exists.

A third option deserves naming: leave the work on the JavaScript thread and slice it into chunks. The price is that the UI thread still shares the budget, and you keep the dropped frames that motivated the library in the first place. The comparison only matters for long synchronous JavaScript; for short, bursty callbacks, none of the three approaches buys much.

MIT licence, uneven release dates, and a build-time coupling to check

The licence is MIT, so the library can be embedded in closed source applications and modified without copyleft obligations on the app that ships it. That is a licensing fact rather than legal advice, and it says nothing about the other native libraries you link alongside it.

On upkeep, the last push was on 2026-04-22 and the repository is not archived. The release history is uneven: v1.6.3 was published on 2026-02-12, while v1.6.2 and v1.6.1 both landed on 2025-08-06, two releases sharing a single day. The version field in package.json reads 1.6.3, matching the newest release tag.

The upgrade surface is worth checking before you commit. Because the worklet marker is interpreted at build time by a Babel plugin and because the npm package ships src, lib and the android and ios folders together, a version bump can touch both babel.config.js and your native build. The example project is wired into the package scripts through the example and bootstrap entries, which is how a contributor brings up a working app, and the CONTRIBUTING.md file points at the development workflow for anything beyond that.

Editorial conclusion

react-native-worklets-core fits one narrow case: a React Native app that owns native C++ code and needs a JavaScript callback to run on another thread, where it makes more sense to depend on it as a peer dependency of a module such as react-native-wishlist than to add it directly. Teams without native code of their own, and teams whose heaviest JavaScript is animation, should look at the runtime already shipped with their app before installing it. Before adopting it, read docs/USAGE.md and docs/WORKLETS.md directly, confirm the plugin entry is registered in babel.config.js, and find out what happens to a worklet that throws or is cancelled, because the top-level documentation does not answer those questions and the last push was on 2026-04-22.

Frequently asked questions

How do I install react-native-worklets-core in a React Native project?

Add the package with yarn add react-native-worklets-core, register the react-native-worklets-core/plugin entry in babel.config.js, and then restart Metro with yarn start --reset-cache so the bundle is rebuilt with the plugin active.

Do I need react-native-worklets-core just to animate my app?

Probably not. The README says the library should in most cases be used as a peer dependency for other modules such as react-native-vision-camera, react-native-wishlist, or react-native-skia, so an app that only needs animation has no reason to add a native worklet runner.

What is a worklet in react-native-worklets-core?

A worklet is a JavaScript function whose body starts with the 'worklet' directive. The Babel plugin registered as react-native-worklets-core/plugin recognises that marker and compiles the function so it can run on a separate thread.

How often is react-native-worklets-core updated and what licence does it use?

The repository is not archived and the last push was on 2026-04-22. The licence is MIT, and the version field in package.json reads 1.6.3, matching the v1.6.3 release published on 2026-02-12.

Where can I see how worklets are scheduled and used?

The README points to USAGE.md for usage and to docs/WORKLETS.md for the Worklet concept, and the repository also ships an example/ project with its own android and ios folders that can serve as a reference call site.

Official sources

  1. License: MIT
  2. margelo/react-native-worklets-core on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/margelo-react-native-worklets-core.svg)](https://hysenlabs.com/projects/margelo-react-native-worklets-core)

Was this useful?