For AI agents: the complete documentation index is available at /next/llms.txt, the full documentation bundle is available at /next/llms-full.txt, and this page is available as Markdown at /next/guide/autolink.md.
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. Before this, those capabilities had to be wired up once per host app, with a separate pass for Android, iOS, and HarmonyOS. Autolink is the companion 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 provides app-wide registration on Android and iOS. HarmonyOS integration is documented below but is not yet available in a released Lynx SDK. Autolink also covers the package metadata and host loading used by Lynxtron native libraries, but does not generate per-LynxView library registration or Web integration code.
This page has two halves: to use an existing library in your app, start from Consuming a Library; to publish your own native capability as a library, start from Authoring a Library. If you would rather understand the machinery first, read How Autolink Works.
Lynxtron: create-lynx-library can generate shared native library packages, and @lynx-js/lynxtron-dev-plugins provides host-side loading through pluginLynxtron().
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.
The following table shows Autolink support for the platforms represented in Lynx Compatibility Data. Lynxtron's host-side integration is documented in Set Up Autolink, but Lynxtron is not represented in this table.
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, iOS CocoaPods plugin, and HarmonyOS Hvigor 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.
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.json is required so the app can declare Autolink library packages as dependencies.
For Android, the project needs a Gradle settings file, such as settings.gradle or settings.gradle.kts, and an Android application build file, such as app/build.gradle or app/build.gradle.kts.
For iOS, the project needs a CocoaPods entry point, usually Podfile. If your team manages Ruby dependencies with Bundler, keep the cocoapods-lynx-library gem in Gemfile.
For HarmonyOS, the project needs a root hvigorconfig.ts and an entry or feature HAP module that depends on @lynx/lynx.
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 compiled dist/ 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 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.
Enable the settings plugin in settings.gradle so library Android projects can be discovered from lynx.lib.json and included:
plugins { id 'org.lynxsdk.lynx.library-settings' version '4.0.1'}
Enable the build plugin in the Android application project so the generated registry is added to the app and library projects are wired as dependencies:
plugins { id 'com.android.application' id 'org.lynxsdk.lynx.library-build' version '4.0.1'}
After Gradle sync/build, Autolink generates a fixed Android registry entry and adds it to the app sources. When the app initializes LynxEnv, that entry is loaded automatically, and Elements, Native Modules, and Services from installed libraries are registered app-wide. App code does not need any additional native 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:
plugin 'cocoapods-lynx-library'target 'LynxApp' do use_lynx_library!end
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.
Add the plugin dependency to hvigor/hvigor-config.json5 in the HarmonyOS project root:
Create hvigorconfig.ts in the HarmonyOS project root and enable the plugin once:
import * as hvigorApi from '@ohos/hvigor';import { enableHarmonyLynxAutolink } from '@lynx/lynx-library-plugin';enableHarmonyLynxAutolink(hvigorApi, { moduleName: 'entry',});
You can omit moduleName when the project has exactly one entry or feature HAP that depends on @lynx/lynx. Projects with multiple Lynx HAP modules must select the target explicitly.
Before Hvigor creates module nodes, the plugin scans visible node_modules directories, parses HarmonyOS JSON5 metadata with Hvigor's public parseJsonFile() API, generates a Registry HAR in the project's ignored .hvigor/lynx-autolink/<moduleName> cache directory, and adds the library and Registry HAR modules to the build graph through hvigorConfig.includeNode(). After the target HAP is evaluated, it uses HAP model APIs to inject the Registry dependency and generated resource directory and set module.appStartup. The AppStartup sources stay under the HAP module's build/generated/lynx-autolink directory; a generated Hvigor task restores them after clean and before the active target's PreBuild. The plugin does not edit the app's src tree or checked-in build-profile.json5 files.
The generated AppStartup task runs on the main thread before app code creates a Lynx runtime and calls only the Registry HAR's idempotent setupGlobal() function. If the HAP already has an AppStartup profile, the plugin preserves its tasks and configEntry and appends the Lynx task. No command such as lynx-harmony-autolink and no manual setupGlobal() call is required.
Lynxtron enables Autolink for Desktop native libraries. Not every Lynx-embedded Desktop host supports Autolink out of the box; this is a Lynxtron-provided integration.
In the Lynxtron host's Rspack config, add pluginLynxtron(). The plugin includes Lynxtron Autolink by default: it scans installed dependencies for lynx.lib.json, copies matching native library packages into the host output, and injects code that imports each copied package's ./lynxtron entry. For packages declared with platforms.lynxtron.path, direct imports of <package>/lynxtron are also aliased to a generated proxy that resolves the copied package at runtime. The ./lynxtron entry loads the current host's .node artifact.
The entry field is the Lynxtron host's own bundle entry, and pluginLynxtron() stages native library packages relative to it. See the @lynx-js/lynxtron-dev-plugins package for the full option shape.
After Lynxtron loads a native library, its Lynx static registrations become available in the Lynx runtime. The library author does not need a Lynxtron-specific registration macro.
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. For HarmonyOS, packageDir defaults to harmony; that directory must contain a complete source HAR with hvigorfile.ts, oh-package.json5, build-profile.json5, src/main/module.json5, and the package entry declared by main or Index.ets.
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 or HarmonyOS 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.
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.json makes the package installable from npm and usually provides the codegen script.
lynx.lib.json is the Autolink contract. It tells the host app where each native package or artifact root lives.
types/index.d.ts re-exports typed Native Module declarations. Platform Native Module declarations live in types/platform-native-module.d.ts, and N-API Native Module declarations live in types/napi-native-module.d.ts when those features are selected.
src/index.ts exports the JavaScript API that app code imports.
android/, ios/, and harmony/ contain native implementations and generated native specs. The HarmonyOS directory is a complete source HAR, including its module-level hvigorfile.ts.
shared/ contains cross-platform native code, such as self-render element implementations and C++ N-API callback stubs under shared/nativeModule/.
lynxtron/ and dist/ contain the Lynxtron loading entry and per-host outputs.
example/ is a local app used by the library author to verify the package.
package.json with "codegen": "lynx-autolink-codegen"
lynx.lib.json for Android, iOS, HarmonyOS, and Lynxtron Autolink metadata
types/index.d.ts, types/platform-native-module.d.ts, and types/napi-native-module.d.ts for typed Native Module declarations, depending on the selected module features
src/index.ts for the JavaScript facade
android/ and ios/ native source folders plus a complete harmony/ source HAR
shared/ native sources when cross-platform implementations are generated
lynxtron/ loading entry when Lynxtron artifacts are generated
example/, tsconfig.json, and README.md
Run codegen from the library root:
npm run codegen
lynx-autolink-codegen reads lynx.lib.json. For Native Modules, it scans the Native Module declaration files under types/ for @lynxmodule declarations:
generated/<ModuleName>.ts for the JavaScript facade
Android <ModuleName>Spec.java for Android platform native modules
iOS <ModuleName>Spec.h and <ModuleName>Spec.m for iOS platform native modules
HarmonyOS <ModuleName>Spec.ets under <packageDir>/src/main/ets/generated
shared C++ N-API callback stubs under shared/nativeModule/ for N-API native modules
The HarmonyOS spec currently supports void, string, number, boolean, and nullable unions with null. Other generated targets retain their existing support for arrays, objects/maps/sets, promises, and N-API wrapped value types such as ArrayBuffer, typed arrays, BigInt, Date, Function, Symbol, Buffer, and Value.
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. HarmonyOS libraries export one provider that registers all capabilities.
Native Module example:
package com.example.button;import com.example.button.generated.ButtonModuleSpec;import com.lynx.jsbridge.LynxNativeModule;import com.lynx.jsbridge.LynxMethod;import com.lynx.tasm.behavior.LynxContext;import java.util.HashMap;import java.util.Map;@LynxNativeModule(name = "ButtonModule")public final class ButtonModule extends ButtonModuleSpec { private final Map<String, Boolean> enabledState = new HashMap<>(); public ButtonModule(LynxContext context) { super(context); } @Override @LynxMethod public String getLabel(String id) { return "Button " + id; } @Override @LynxMethod public void setEnabled(String id, boolean enabled) { enabledState.put(id, enabled); }}
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(...).
HarmonyOS libraries register all capabilities from one provider. Index.ets must export a class named LynxLibraryProviderImpl:
// harmony/Index.etsexport { LynxLibraryProviderImpl } from './src/main/ets/LynxLibraryProviderImpl';export { ButtonElement } from './src/main/ets/ButtonElement';export { ButtonModule } from './src/main/ets/ButtonModule';export { ButtonService } from './src/main/ets/ButtonService';
Implement a Native Module by extending the generated ArkTS spec:
The provider connects those implementations to Lynx:
import { Behavior, LynxLibraryProvider, LynxLibraryRegistry, LynxServiceType,} from '@lynx/lynx';import { ButtonElement } from './ButtonElement';import { ButtonModule } from './ButtonModule';import { ButtonService } from './ButtonService';export class LynxLibraryProviderImpl implements LynxLibraryProvider { register(registry: LynxLibraryRegistry): void { registry.registerBehavior('x-button', new Behavior(ButtonElement)); registry.registerModule('ButtonModule', { moduleClass: ButtonModule }); registry.registerService(LynxServiceType.Extension, ButtonService.instance); }}
Use registerInitializer(() => packageInit()) for package-level native initialization such as a native XElement registration API. Keep native XElements on their existing C++ registration path; do not wrap them in a UIBase implementation just for Autolink.
The Registry rejects duplicate global Element tags, Native Module names, and Service types with package-aware diagnostics. Global Native Modules are installed before a LynxView or LynxBackgroundRuntime's explicit module map, so an explicitly supplied local module keeps its existing override behavior.
Lynxtron native libraries use the shared Lynx C/C++ extension APIs and static registration macros. This page only covers how Autolink discovers and loads packages. For implementation details, use the Desktop (Node-API) tab for Native Modules and the Desktop tab for Custom Native Elements:
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.
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. Generation works differently per 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.
HarmonyOS: registry generation runs during Hvigor configuration and emits a source Registry HAR plus an AppStartup task.
Lynxtron: Autolink runs in the host Rspack build, staging matching native packages, injecting a loader into the host bundle, and letting the loaded library's Lynx static registrations provide its native modules and elements.
Android, iOS, and HarmonyOS load their generated registry once during initialization, so no per-library wiring code lives in the host.
Except as otherwise noted, this work is licensed under a Creative Commons Attribution 4.0 International License, and code samples are licensed under the Apache License 2.0.