Skip to content
neuralSPOT-X
User guide
HELIA HUB

Using modules

A module is a reusable unit of firmware with a manifest that says what it provides, what it needs and what it declares compatibility with. An app’s nsx.yml lists the modules you asked for directly. Everything else in the build arrives because something you asked for needed it.

The module catalog is the full list with a page per module. This page is about working with them from inside an app.

The mental model is familiar from pip, Cargo and npm: discover a dependency, declare it in a project, resolve its dependencies and record the result. NSX uses that workflow for firmware sources and build integration.

Concept NSX
Project manifest nsx.yml declares the app’s targets and direct modules.
Module manifest nsx-module.yaml declares a module’s dependencies and compatibility.
Registry Packaged metadata maps module names to source projects and revisions; apps can override it.
Lockfile nsx.lock records resolved sources and hashes.
Local dependencies modules/ holds the sources the app builds with.
Build integration CMake connects the selected modules to the firmware target.

The analogy is about dependency management. NSX does not install Python wheels, npm packages or Cargo crates as firmware modules. In the embedded world, Zephyr modules serve a similar composition role, but NSX uses its own manifests and AmbiqSuite provider. A library’s NSX integration and its Zephyr integration are separate entry points.

nsx create-app records the board, and the board’s starter profile is layered in as an implicit baseline: the SoC HAL, the BSP, the CMSIS startup pieces and the runtime core. None of that appears in your modules: list, because it is not something you chose. It is what building for that board means.

Your declarations are additive on top of that baseline. If you want the baseline gone entirely, nsx.yml accepts one opt-out:

baseline: none

That is what --no-bootstrap writes. With it the app depends on exactly what you list and nothing else, which is a reasonable starting point for a bring-up and a poor one for a first app.

Terminal window
nsx module list # what this app depends on
nsx module list --json # the same, machine readable
nsx module list --registry-only # every module NSX knows about

nsx list-modules is an alias for the same command.

nsx module describe <name> prints one module’s manifest in full: its type, version, what it provides, its dependencies, and the boards, SoCs and toolchains it declares compatibility with. --json gives the same content as data.

nsx module search <query> matches across names, summaries, capabilities, use cases and the author’s own keywords, so it finds modules by what they do rather than by what they are called.

Terminal window
nsx module add nsx-uart

nsx add is an alias. The command appends the module to nsx.yml, then re-resolves and syncs, so modules/ and nsx.lock both catch up.

Two refusals are common and both mean what they say:

Module 'nsx-uart' is already a direct dependency in nsx.yml
--board apollo4p_evb not in the app's supported targets (apollo510_evb)

--dry-run shows the changes without writing them.

--board is repeatable and restricts the dependency to the boards you name:

Terminal window
nsx module add nsx-ble --board apollo4p_blue_kxr_evb --board apollo510b_evb

In nsx.yml that becomes an entry with a boards list. Boards outside the list resolve without it, which is how one manifest serves targets with different radios or peripherals. An entry with no boards applies to every target.

Terminal window
nsx module remove nsx-uart

This removes your direct declaration. If another module in the graph still requires it, it stays in the closure and keeps building, which is correct: you stopped asking for it, but something else still needs it. nsx module list shows direct dependencies, so the module disappearing from that list while remaining in modules/ is expected.

Terminal window
nsx outdated # which git-backed modules lag their upstream tip
nsx module update # re-resolve and re-vendor

nsx outdated only has something to say about modules backed by a git constraint, because a packaged or vendored module has no upstream tip to compare against. --json reports checked, skipped and outdated_count, and --exit-code makes it fail a CI job.

Lock and sync covers the resolution and pinning behind all of this, including how to pin a module to an exact revision.

Optional dependencies are information, not installs

Section titled “Optional dependencies are information, not installs”

Only depends.required is resolved. A manifest’s depends.optional is searchable metadata, so a module you expected to arrive may not have. See the dependency model.

Source What it means How you get it
Registry A module NSX pins in its packaged registry, fetched from git or shipped inside the wheel. The default. nsx module add <name>.
Local path A module you are developing, on disk outside the app. NSX mirrors it into modules/ on every sync. nsx module add <name> --local --path <dir>
Vendored A module whose sources live in your repository. nsx sync leaves it alone. nsx module add <name> --vendored

An app can also override where the registry points for a given module, which is how you test a fork without touching NSX itself. Custom modules covers all three cases and how to write a module of your own.

A module’s compatibility.boards, compatibility.socs and compatibility.toolchains come from the manifest its author wrote. NSX enforces them, so an incompatible combination is rejected rather than silently built, but enforcement is against the declaration. It is not evidence that the module was run on that board.