If you have ever tried to publish a React Native library by hand, you know the project starts long before the interesting part. Before you write any feature code, you are stuck wiring up a Gradle build, a Podspec, a Codegen spec for the new architecture, a TypeScript config, an example app to test against, a CI workflow, and a package.json that actually publishes the right files. It is a lot of plumbing, and most of it is identical from one library to the next.
Create React Native Library is Callstack's answer to that problem. It is a CLI, published on npm as create-react-native-library, that scaffolds a complete, publishable React Native library for you. You run one command, answer a few questions, and it generates a project that is already wired for React Native's new architecture, ships with an example app, and uses Callstack's companion build tool react-native-builder-bob to produce distributable output. It is the tool the React Native docs themselves point library authors toward, and it stays current with where the platform is heading: Turbo Modules, Fabric components, and now Nitro modules.
What You Actually Get
The CLI is not just a folder of templates. It makes a series of decisions on your behalf and configures them correctly so they work together. A freshly scaffolded library gives you:
- New-architecture-ready native folders for iOS and Android, matching the library type and language you picked.
- An example app that already consumes your library, so you can run and test it immediately rather than building a harness yourself.
- react-native-builder-bob configured as the build step, producing CommonJS, ES module, and TypeScript type-definition outputs.
- TypeScript, ESLint, and Prettier set up out of the box.
- A publish-ready
package.jsonplus a GitHub Actions CI workflow and release tooling.
The headline value is that all of this is consistent and correct. The boilerplate for a new-architecture native module, in particular, is fiddly and easy to get subtly wrong. Letting the CLI generate it removes an entire category of "why won't my module link" frustration.
The Two-Part Workflow
It helps to understand that Callstack splits the job across two packages. create-react-native-library is the scaffolder; it runs once when you start a project. react-native-builder-bob is the build tool; it lives inside your library as a dependency and runs every time you build for distribution.
That division is why their download numbers look so different. The scaffolder sees modest traffic because you only run it to start a project. Builder Bob, on the other hand, is pulled in by every library it scaffolds, so it racks up hundreds of thousands of weekly downloads as a build dependency. When you publish, Bob is the piece quietly transpiling your source into the formats consumers expect.
Getting Started
You do not install the CLI globally. The idiomatic approach is to run it directly with your package runner of choice.
# npm
npx create-react-native-library@latest awesome-library
# yarn
yarn create react-native-library awesome-library
Both forms launch the same interactive flow. The CLI asks for the package name, a description, your author details, and the repository URL, then moves on to the more interesting questions: what kind of library you are building and in which languages.
Picking a Library Type
This is where the tool earns its keep. The new architecture offers several ways to expose native capability to JavaScript, and the CLI lets you choose the right one up front instead of refactoring into it later.
A Plain JavaScript Library
If your library is pure TypeScript or JavaScript with no native code, pick the JS library type. You get the build, lint, and publish setup without any iOS or Android folders. This is the lightest option and the right one for utilities, hooks, or anything that lives entirely in the JS layer.
A Turbo Module for Native Logic
When you need performance-critical native code or access to a platform API, a Turbo Module is the modern choice. Turbo Modules use Codegen to generate native interfaces from a TypeScript spec, so your JS and native sides stay in sync and talk directly through JSI. The CLI scaffolds the spec file and the native glue for you.
// src/NativeAwesomeLibrary.ts
import type { TurboModule } from "react-native";
import { TurboModuleRegistry } from "react-native";
export interface Spec extends TurboModule {
multiply(a: number, b: number): number;
}
export default TurboModuleRegistry.getEnforcing<Spec>("AwesomeLibrary");
This TypeScript spec is the contract. Codegen reads it and produces the corresponding native interfaces, which the generated Kotlin, Swift, Objective-C, or C++ implementation then fills in.
A Fabric View for Custom UI
If your library renders a custom native view, choose the Fabric component type. Fabric views are React Native's new-architecture rendering path, backed by a C++ ShadowNode for efficient layout and prop handling. The scaffold gives you a native view component and the JS side that mounts it.
A Nitro Module for Less Boilerplate
A more recent addition is support for Nitro modules. Nitro, from the margelo team, builds on JSI and the new architecture with a strong focus on developer experience: less boilerplate, type-safe native bindings, and fast prop parsing. If you want the new-architecture benefits with a friendlier authoring experience, the CLI can scaffold a Nitro-based module directly.
Choosing Your Languages
Once you have picked a type, the CLI asks which native languages to use. For a Turbo Module you can choose:
- Kotlin and Objective-C
- Kotlin and Swift
- C++, for a single cross-platform implementation shared across iOS and Android
The C++ option is the interesting one for libraries that wrap a cross-platform native dependency or that you simply do not want to write twice. You implement the logic once in C++ and it serves both platforms, with the generated Codegen glue connecting it to JavaScript on each side.
Picking an Example App
A library is only as trustworthy as the app you tested it in, so the scaffold always includes one. The CLI offers a few flavours:
- React Native Community CLI — a standard vanilla app.
- Expo — an Expo-managed app, with an Expo Web option if you want to exercise the web target too.
- React Native Test App — a lightweight harness from
react-native-test-appthat lets you test without committing a full application to your repo.
The Test App option is worth knowing about. Instead of carrying an entire example application in version control, it provides a thin, regenerable host, which keeps your repository smaller and your example focused.
Building a Module Inside an Existing App
Not every native module is destined for npm. Sometimes you just need a bit of native code inside an app you are already building. For that, the CLI has a local mode.
npx create-react-native-library@latest awesome-library --local
With --local, the tool generates the library inside your existing project's modules folder rather than as a standalone publishable package. You get the same well-formed native scaffolding, minus the publishing machinery you would not use. It is the fastest way to add a proper Turbo Module to an app without leaving the repo.
When You Need the Old Architecture
The current CLI is built around the new architecture, which is correct for almost all new work. If you specifically need to target the legacy bridge-based native module setup, the documented path is to pin an older release of the tool.
npx create-react-native-library@0.49.8 awesome-library
This is an escape hatch rather than a recommendation. New libraries should target the new architecture, but it is good to know the option exists for maintaining or matching an older codebase.
Building and Publishing
After scaffolding, your day-to-day build runs through Builder Bob, which is already configured in the generated project. Its job is to take your src and emit the output targets that consumers rely on, so a library works whether the host project uses CommonJS or ES modules and gets full type definitions either way.
yarn prepare
The generated prepare script invokes Bob to produce the build artifacts, and the package.json is set up so that only those artifacts ship to npm. Combined with the release tooling the scaffold includes, the path from "feature complete" to "published" is mostly a matter of running the commands that are already there.
Why Reach For It
The honest pitch for Create React Native Library is that it removes a class of work that has no upside to doing by hand. There is no competitive advantage in hand-wiring a Podspec or hand-writing a Codegen spec; there is only the risk of getting it slightly wrong and losing an afternoon. By generating a consistent, current, new-architecture-ready project, the CLI lets you spend your attention on the part of the library that is actually yours.
It also tracks the platform closely. Because Callstack maintains it alongside their broader React Native work, the supported types follow the ecosystem: Turbo Modules and Fabric when those became the path forward, and Nitro as it matured. Picking this tool means your starting point reflects where React Native is now, not where it was three releases ago.
If you are starting a React Native library of any kind, from a tiny JS utility to a cross-platform C++ Turbo Module, this is the place to begin. Run the command, answer the questions, and start with the boring parts already solved.