Native Libraries and Autolink
A Lynx native library is an npm package that ships any combination of Elements, Native Modules, and Services for a host Lynx app to consume. Autolink is the integration mechanism that lets the host app discover libraries installed under node_modules and connect their native capabilities without wiring each Element, Native Module, or Service by hand.
Autolink covers Android and iOS native app integration, and it also covers the package metadata used by Lynxtron native libraries. It does not generate Web or HarmonyOS integration code.
✅ Completed Integrate with Existing Apps
✅ Familiar with Native Modules and Custom Native Element
Use Autolink tooling from the same Lynx release channel as your app. The package and plugin names are:
- npm:
create-lynx-libraryand@lynx-js/autolink-codegen(lynx-autolink-codegenbinary) - Android: Gradle plugins
org.lynxsdk.library-settingsandorg.lynxsdk.library-build - iOS: Ruby gem
cocoapods-lynx-library - Lynxtron:
create-lynx-librarycan generate shared native library packages, and@lynx-js/lynxtron-dev-pluginsprovides host-side loading throughpluginLynxtron().
If one of these packages cannot be resolved from your configured registries, your current Lynx SDK release does not include Native Autolink in that registry yet. Keep using the existing manual native registration flow until the matching release is available.
What Is a Lynx Native Library
A library is an npm package that may ship any combination of:
- Elements: custom native UI elements rendered by Lynx, such as
<x-button>. - Native Modules: typed JavaScript-to-native APIs callable from Lynx app code.
- Services: app-wide native singletons that other library capabilities can depend on.
Every library declares its native entry points in a lynx.lib.json manifest at the package root. The three capability types are independent: a library may expose only Elements, only Native Modules, only Services, or any combination of them.
App teams install a library like any other npm dependency. The Android Gradle plugins and the iOS CocoaPods plugin read lynx.lib.json and link the native code into the host app, so the host never needs to know which specific capabilities any given library exposes. Lynxtron reads the same manifest from installed packages, stages matched package files into the host output, and prepends generated host-bundle code that requires each staged package's ./lynxtron entry.
Consuming a Library
This section is for app teams integrating one or more libraries into a host Lynx app.
Host App Project Structure
Before enabling Autolink, make sure the host app has a project root that can install npm packages and expose the native app build entry points. A typical host app looks like this:
package.jsonis required so the app can declare Autolink library packages as dependencies.- For Android, the project needs a Gradle settings file, such as
settings.gradleorsettings.gradle.kts, and an Android application build file, such asapp/build.gradleorapp/build.gradle.kts. - For iOS, the project needs a CocoaPods entry point, usually
Podfile. If your team manages Ruby dependencies with Bundler, keep thecocoapods-lynx-librarygem inGemfile. shared/is used when the host app owns cross-platform native source code and CMake build entry points; build these sources yourself.- For Lynxtron, the app needs a host-side Rspack build that can install npm packages and load native libraries through
pluginLynxtron(); it generally consumes the compileddist/artifacts.
After you install dependencies, Autolink scans the installed npm packages for lynx.lib.json files at package roots. A lockfile such as package-lock.json, pnpm-lock.yaml, or yarn.lock is recommended for reproducible installs, but it is not required by Autolink.
Set Up Autolink
Set up Autolink once in the host app. After that, installed library packages can be discovered from node_modules and registered through the generated registry during Lynx initialization.
Install the cocoapods-lynx-library gem in your iOS build environment. Then add the CocoaPods plugin to the app's Podfile and call use_lynx_library! so podspecs from installed libraries and the generated registry pod are added during pod install:
After pod install, Autolink generates the registry pod and hooks it into the Lynx initialization flow. When the app creates LynxConfig or initializes LynxEnv, Elements, Native Modules, and Services from installed libraries are registered automatically. App code does not need to import generated files or add extra native initialization.
Install a Library
After the app has set up Autolink, install the library package in your Lynx app:
Each library package exposes a lynx.lib.json manifest at the package root. Autolink scans installed npm packages for this file.
For Android, platforms.android.packageName is required, and sourceDir defaults to android. For iOS, sourceDir defaults to ios, and podspecPath defaults to the first .podspec found under the iOS source directory.
platforms.macos.sourceDir and platforms.windows.sourceDir point to the source-exposed shared/ directory, which is the cross-platform native source layout and may be reused by more platforms later.
For Lynxtron, platforms.lynxtron.path declares the native artifact root, usually dist. pluginLynxtron() stages matching package files and verifies the artifacts; the package's ./lynxtron export loads the current host's .node, such as dist/macos/arm64/lynx-button.node or dist/windows/x64/lynx-button.node.
After installing or updating a library package, sync/build the Android app and run pod install for iOS so the generated registry and native dependencies are refreshed. You do not need to add per-library manual registration code in the app.
Authoring a Library
This section is for library authors building a reusable native package for other Lynx apps to install.
Library Package Structure
A typical library package looks like this. shared/ is for cross-platform native implementations, and packages that also ship Lynxtron native artifacts may contain a Lynxtron loading entry and per-host outputs:
package.jsonmakes the package installable from npm and usually provides thecodegenscript.lynx.lib.jsonis the Autolink contract. It tells the host app where Android and iOS source code lives, and where the Lynxtron native artifact root lives.types/index.d.tsre-exports typed Native Module declarations. Platform Native Module declarations live intypes/platform-native-module.d.ts, and N-API Native Module declarations live intypes/napi-native-module.d.tswhen those features are selected.src/index.tsexports the JavaScript API that app code imports.android/andios/contain native implementations and generated native specs.shared/contains cross-platform native code, such as self-render element implementations and C++ N-API callback stubs undershared/nativeModule/.lynxtron/anddist/contain the Lynxtron loading entry and per-host outputs.example/is a local app used by the library author to verify the package.
Create a Library
Create a new library package interactively:
For scripts and tests, the same scaffold can run without prompts:
The generated package includes:
package.jsonwith"codegen": "lynx-autolink-codegen"lynx.lib.jsonfor Android, iOS, and Lynxtron Autolink metadatatypes/index.d.ts,types/platform-native-module.d.ts, andtypes/napi-native-module.d.tsfor typed Native Module declarations, depending on the selected module featuressrc/index.tsfor the JavaScript facadeandroid/andios/native source foldersshared/native sources when cross-platform implementations are generatedlynxtron/loading entry when Lynxtron artifacts are generatedexample/,tsconfig.json, andREADME.md
Run codegen from the library root:
lynx-autolink-codegen reads lynx.lib.json. For Native Modules, it scans the Native Module declaration files under types/ for @lynxmodule declarations:
It generates:
generated/<ModuleName>.tsfor the JavaScript facade- Android
<ModuleName>Spec.javafor Android platform native modules - iOS
<ModuleName>Spec.hand<ModuleName>Spec.mfor iOS platform native modules - shared C++ N-API callback stubs under
shared/nativeModule/for N-API native modules
Codegen supports primitive values, nullable unions with null, arrays, objects/maps/sets, promises, and N-API wrapped value types such as ArrayBuffer, typed arrays, BigInt, Date, Function, Symbol, Buffer, and Value.
Write Native APIs
Use platform-specific Lynx annotations or registration APIs in native source files so Autolink can discover each library's capabilities. On Android and iOS, Native Modules usually extend the spec generated by lynx-autolink-codegen, and Elements and Services are discovered from their native markers.
Native Module example:
Element example:
Service example:
On iOS, Autolink scans @LynxNativeModule(...), @LynxElement(...), and @LynxService(...) declarations from library sources and adds the discovered capabilities to the generated registry. The legacy iOS Service API still provides @LynxServiceRegister(...) for existing code. New library code should use @LynxService(...).
Distribute a Library
Publish the library like any other npm package: pick a name, often scoped as @example/lynx-button, set a version in package.json, and run npm publish. App teams add the published version to their package.json and Autolink picks the library up the next time they install dependencies. Pin a compatible Lynx SDK version range in the library's peerDependencies so app teams get a clear signal when the library and the host SDK drift apart.
How Autolink Works
Autolink runs at build time. It scans every npm package under node_modules for a lynx.lib.json manifest, then generates or feeds host integration data for the current platform. Android registry generation runs through the Gradle settings and build plugins; iOS registry generation runs through the CocoaPods plugin and emits a registry pod. The host app loads the generated registry once during LynxEnv initialization, which is why no per-library wiring code lives in the Android or iOS host. Lynxtron Autolink runs in the host Rspack build: it stages matching native packages, injects a loader into the host bundle, and lets the loaded library's Lynx static registrations provide its native modules and elements.