Fills in an existing react-native-builder-bob / create-react-native-library
turbo-module project with the op-sqlite architecture: a TurboModule used
only as a thin, blocking-synchronous install() entry point that hands the
JSI Runtime and CallInvoker to hand-written C++. The actual API surface is
plain JSI — HostObjects and HostFunctions — not codegen'd TurboModule
methods. This avoids the serialization overhead and per-method codegen
boilerplate of a normal TurboModule, at the cost of writing the JSI glue by
hand.
This tool does not scaffold a new npm package from scratch — it replaces
the default example TurboModule inside a project that
create-react-native-library already generated. Create that project first:
npx create-react-native-library@latest react-native-acme-kit \
--type turbo-module --languages kotlin-objcThis is a tool for pure C++ modules only — no Swift/Kotlin API surface, no Nitro/Expo module conventions. If you want a "normal" TurboModule or Nitro module, this isn't the tool for that.
- A per-HostObject
ThreadPool+promisify()helper for async work: background thread does the blocking work,CallInvoker::invokeAsynchops back to the JS thread to resolve/reject thePromise. HFN/HFN2/HFN3HostFunction-creation macros, prefixed with your module's chosen prefix so they can't collide with another native module's macros in the same translation unit.- iOS (Objective-C++ TurboModule + podspec) and Android (fbjni JNI bridge +
Kotlin TurboModule + CMake/prefab
build.gradle) wiring, with no codegen required for anything beyond the singleinstall()call. - Every generated identifier — C++ namespace, class/file names, the JNI
class descriptor, the
global.__{Prefix}ProxyJS bridge object, the Android log tag — is stamped with a prefix you choose, so the generated module can't collide with another native module's symbols in the same app. to_jsi()/to_variant()in{Prefix}Utils.hpp: the single place every JSI <-> C++ conversion goes through, built on aJSVarianttype (in{Prefix}Types.hpp) you extend as needed, instead of hand-rolledjsi::Valuereads/writes scattered across HostFunctions. Prefixed so it can't collide with another pure-C++ module's owntypes.hpp/utils.hppin the same app.create_object_array(): builds an array of same-shaped objects (e.g. query-result rows) by creating each column'sjsi::PropNameIDonce, outside the row loop, instead of re-interning the same property name once per cell — a real performance win once you're returning more than a handful of rows.- An
ExampleHostObjectshowing all three patterns: a synchronous method (add), an async method (computeAsync) built withpromisify(), and a method returning an object array (labelItems) built withto_string_vec()+create_object_array().
Inside the react-native-acme-kit directory create-react-native-library
just created:
npx create-pure-module \
--prefix Acme \
--package com.acme.kit--dir defaults to .; pass it to point at a different existing project.
The command refuses to run (unless you pass --force) if the target
directory doesn't have a package.json with a react-native-builder-bob or
create-react-native-library key — that's the signal it uses to confirm
there's an existing scaffold to fill in rather than an empty directory.
Omit --prefix/--package and it'll prompt for them interactively (as long
as stdin is a TTY); --package defaults to whatever
codegenConfig.android.javaPackageName is already in the project's
package.json. See SKILL.md for the full list of files it generates and
removes.
This repo is also a Claude Code skill
(skills/create-pure-module/SKILL.md). Install it into a project with the
skills CLI:
npx skills add OP-Engineering/pure-module-skillThis copies skills/create-pure-module/ into .claude/skills/ (or the
equivalent directory for your agent) and Claude can drive the scaffolding
interactively via /create-pure-module. You can also drop the
skills/create-pure-module/ directory in by hand into .claude/skills/
in a project (or a personal ~/.claude/skills/).
create-react-native-library already bundled an example/ app that depends
on the library locally, so there's no separate test app to wire up:
yarn installat the project root (picks up thecodegenConfigchange).- iOS:
cd example/ios && pod install(oryarn podsfrom the root, ifcreate-react-native-libraryset that script up). - Android: build normally — prefab headers are wired up already.
Extend it by adding new HostObjects under cpp/ (copy
ExampleHostObject as a starting point) and registering them in
{Prefix}Module.cpp's install(). No codegen changes needed for new
methods.
MIT