Skip to main content

Nitrogen

Nitrogen is Nitro's code-generator. It parses TypeScript code using an AST parser to generate native interfaces from TypeScript definitions.

Math.nitro.ts
@iOS(...)
@Android(...)
export declare class Math extends HybridObject {
readonly pi: number
add(a: number, b: number): number
}
export * from '#nitro/Math'
HybridMathSpec.swift (generated excerpt)
public protocol HybridMathSpec_protocol: HybridObject {
var pi: Double { get }
func add(a: Double, b: Double) throws -> Double
}

When HybridMathSpec is not implemented properly on the native side (e.g. if add(..) is missing, or if a type is incorrect), the app will not compile, which ensures full type-safety and null-safety at compile-time.

Nitrogen is optional​

Nitrogen is a fully optional CLI that does some of the work for you. You can also build Nitro Modules and create Hybrid Objects without nitrogen, by just registering the HybridClass yourself.

Who uses Nitrogen?​

Nitrogen should be used by library-authors, and generated specs should be committed to the repository/package.

If you build an app that uses libraries built with Nitro, you do not need to run nitrogen yourself.

Configuration​

Nitrogen should be installed as a dev-dependency in the Nitro Module (library).

npm i nitrogen --save-dev

Each Nitro Module needs to have a nitro.json configuration file.

Create a nitro.json file in the root directory of your Nitro Module (next to package.json), and add the following content:

nitro.json
{
"$schema": "https://nitro.margelo.com/nitro.schema.json",
"cxxNamespace": ["math"],
"ios": {
"iosModuleName": "NitroMath"
},
"android": {
"androidNamespace": ["math"],
"androidCxxLibName": "NitroMath"
}
}

Usage​

Nitrogen parses all TypeScript files that end in .nitro.ts.

1. Write TypeScript specs​

A Nitro spec file consists of one or more declare class statements and combined exports.

  • declare class describes your native class via instance methods, properties (get + set), constructor(...), or static methods.
  • The @iOS and @Android decorators on declare class describe the connection between the JS types and the native implementation - for example, language: 'swift' means that Math is implemented in Swift on iOS. implementation: ... defines the actual Swift class that implements the spec natively, which is required for it to have a constructor() or static methods.
  • Since declare class is type-only, no JS runtime code exists. Nitrogen generates this, which must be re-exported via export * from '#nitro/Math'.

See Platform decorators for all @iOS and @Android options, including multiple implementations, inheritance, and native protocol/interface requirements.

Math.nitro.ts
import { iOS, type HybridObject } from 'nitro-core'

@iOS({
language: 'swift',
implementation: { className: 'HybridMath' }
})
export declare class Math extends HybridObject {
// Public constructor: new Math()
constructor()
// Static method: Math.add(5, 3)
static add(a: number, b: number): number

// Get-only instance property: math.pi
readonly pi: number
// Instance method: math.multiply(5, 3)
multiply(a: number, b: number): number
}
export * from '#nitro/Math'

2. Generate native specs​

Now run nitrogen:

npx nitrogen

This generates the shared C++ specs, platform bindings, and JavaScript class exports in ./nitrogen/generated/. Run Nitrogen before compiling TypeScript so the generated modules and their declarations exist:

🔧 Loading nitro.json config...
🚀 Nitrogen runs at ~/Projects/nitro/example/dummy
🔍 Nitrogen found 1 spec in ~/Projects/nitro/example/dummy
⏳ Parsing Math.nitro.ts...
⚙️ Generating specs for HybridObject "Math"...
shared: Generating C++ code...
🎉 Generated 1/1 HybridObject in 0.6s!
💡 Your code is in ./nitrogen/generated
‼️ Added 8 files - refresh SwiftPM (`npx react-native spm` for React Native) or sync Gradle to update files!
important

Commit ./nitrogen/generated/ and include it in your npm package, including the .cjs runtime modules and .d.cts declarations in shared/javascript/. If you use a files list in package.json, add nitrogen/generated to it. Consumers use these files without running Nitrogen themselves.

3. Add generated sources to your library​

All the generated sources (./nitrogen/generated/) need to be part of your library's code - so we need to add it to the iOS/Android build files.

If you created a library using the Nitro Module template, your library already includes nitrogen's generated sources.

4. Implement the Hybrid Objects​

To implement Math now, you just need to implement the spec:

HybridMath.swift
import NitroModules

final class HybridMath : HybridMathSpec {
static func add(a: Double, b: Double) throws -> Double {
return a + b
}

var pi: Double { Double.pi }

func multiply(a: Double, b: Double) throws -> Double {
return a * b
}
}

5. Use the Hybrid Objects​

Static methods are directly callable on the Math type:

import { Math } from './Math.nitro'

const result = Math.add(5, 7) // 12

Since Math has a constructor(), we can create instances of it with new:

import { Math } from './Math.nitro'

const math = new Math()
math.pi // 3.1415
math.multiply(5, 3) // 15

Lastly, expose the class to consumers through your library's entry point:

src/index.ts
export { Math } from './specs/Math.nitro'