Tutorial · C++ · Python · Version 0.2.0
Use a Holoscan Module
End-to-end walkthrough to consume a Holoscan SDK 5 Module from a standalone CLI project or external CMake project.
| Authors | Holoscan Team (NVIDIA) |
|---|---|
| Supported platforms | x86_64, aarch64 |
| Language | C++, Python |
| Version | 0.2.0 |
| Compatibility | HSDK 5.0 |
| Contribution level | Level 1 · Very high-quality code |
| Source | holoscan-tutorials |
In this tutorial you will learn how to consume a Holoscan Module from a downstream project built on the Holoscan SDK. We will walk through declaring the dependency, installing or building the Module, and importing its operators in your own code.
1. Holoscan Modules in Context
What is NVIDIA Holoscan?
Holoscan SDK is NVIDIA's platform for building streaming, low-latency AI pipelines targeting medical devices, robotics, and industrial edge systems. Applications in the ecosystem are composed of operators — discrete processing units connected into a directed acyclic graph (DAG) by the SDK's pipeline executor.
What is a Holoscan Module?
A Holoscan Module is a distributable project library of one or more related operators, subgraphs, or other components to extend the Holoscan SDK application programming interface (API). A module may be packaged and published so that other Holoscan applications can consume it as a binary dependency. It is a way to share reusable Holoscan processing blocks beyond a single application or repository. The import and build integration depend on which C++ and Python artifacts the Module maintainer publishes.
# For an SDK 5 Module generated with --language cpp python:
from holoscan_my_sensor.operators import MySensorOp
The primary form of a Module is a standalone External Module — a git repository with its own operators, applications, tests, packaging, and CI. Consumers fetch its sources at build time or install a published binary package.
In this tutorial we use a fictional holoscan-my-sensor external Module as the running
worked example. Its URLs, package names, and commit SHA are placeholders, not a published
release. Substitute a real Module, or create one with the companion tutorial.
Who consumes a Holoscan Module?
A Holoscan Module is the right dependency to declare when:
- You are building a library or end-user product on the Holoscan SDK and need and want versioned, supported operators rather than vendored or copy-pasted source.
- You are building a Holoscan sample application that needs hardware-specific or domain-specific operators — for example, a robotics application that needs a vendor camera driver, or a medical-imaging app that needs an image-reconstruction library.
- You are building another Holoscan Module whose operators depend on operators from an upstream Module (a transitive dependency).
In each case the goal is the same: pick up a versioned set of operators by referencing them in metadata or installing a binary package, without forking source or maintaining build glue.
Why use a Holoscan Module instead of copy-pasting operators or rolling your own?
- Versioned and supported. The Module's maintainer owns its build, ABI, test, and release. You consume a pinned commit (source build) or a pinned package version (binary install) and get bug fixes and SDK-compatibility updates for free.
- Discoverable. Curated Holoscan Modules may be listed alongside SDK-supported and community work on the NVIDIA Holoscan ecosystem website. Prospective users and their AI agents find your dependency choices by searching the Holoscan ecosystem instead of guessing repo names. A vendored copy puts the entire burden of discovery on you.
- Drop-in. The Holoscan CLI reads Module metadata and prepares source declarations
for your CMake build (Path C). Binary consumers get the same operators
via standard
pip installorapt installplus a singlefind_package(C++) orimport(Python). No vendor-specific build glue.
A Holoscan Module dependency gives you all of the above by adopting a small set of conventions (the metadata schema and dependency-resolver flow described below).
2. Tutorial Prerequisites
This tutorial covers several approaches to consume a Holoscan Module in your project. The base prerequisites apply to all paths; each path's section below calls out anything extra it needs.
- The target Holoscan Module — its name (e.g.,
holoscan-my-sensor), its source URL or its published binary package name, and either a release commit SHA (source build) or a binary package version (install flows). - Holoscan SDK >= 5.0.0 matching the Module's
metadata.json:module.holoscan_sdk.minimum_required_version. - Python >=3.12 for Holoscan CLI. Binary consumers follow the Python requirements of their SDK and module wheels.
- For Path C, install the Holoscan CLI
in the consuming project's development environment. The examples use
holoscan-cli==5.0.0, matching the Create a Module tutorial.
Container Approach (Recommended for the CLI Workflow)
- Docker, including the buildx plugin (
docker-buildx-plugin) - the NVIDIA Container Toolkit (v1.14 or later)
- A local clone of the consuming Holoscan project, with its documented development container.
Local Approach (for External C++ / Python / Source-Embedding Flows)
- CMake >= 4.0
- GCC >= 13, or another a C++20-capable toolchain for C++ and source-embedding flows.
uv, orpipand a Holoscan SDK wheel installed in the same environment for the Python flow.- Network access during CMake configure for the source-embedding flow.
3. Available Approaches
The Create a Module tutorial provides a project template with a few standard distribution mechanisms, including source distribution, Debian packaging, or (in the future) Python wheels. Below we discuss a few recommended options for using an external Module in a downstream project. The Holoscan Module maintainer is ultimately responsible to document and maintain the supported distribution paths for their Module.
Pick the path that matches your project, then jump to the corresponding section.
| Your project is… | Use… |
|---|---|
| A standalone C++ application using a module binary package | Path A (§4) |
| A standalone C++ project using module sources | Path B (§5) |
| A Holoscan sample application using Holoscan CLI dependency metadata | Path C (§6) |
| Another Holoscan Module declaring a transitive dependency with Holoscan CLI | Path C (§6.7) |
| A pure-Python application or notebook | Path D (§7) |
4. Path A — External C++ Project (Binary Install)
Standalone Holoscan projects can consume Module binaries like any other binary package. A Holoscan Module created from template can support Debian C++ binary packaging out of the box.
4.1 Install the binary
Review the Module's metadata.json:module.binary_packages for recommended installation commands.
For a Module actually published to your configured APT repository, the installation command
might be:
# Debian / Ubuntu
apt install holoscan-my-sensor
4.2 CMake integration
In your project's CMakeLists.txt:
find_package(holoscan REQUIRED COMPONENTS core)
find_package(holoscan-my-sensor REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE
holoscan::core
holoscan::my_sensor_op
)
Modules are responsible for shipping a CMake package config — for example,
/usr/lib/<triplet>/cmake/holoscan-my-sensor/holoscan-my-sensor-config.cmake — that
exports targets under the holoscan:: namespace. Consult the Module's repository for its
exported targets and package-consumption examples.
If the package is not found, ensure the install prefix is on CMAKE_PREFIX_PATH, or
that you installed via the system package manager into a default-searched prefix
(typically /usr). Report any issues to the appropriate module repository maintainer.
5. Path B — Source-Level Embedding in a Fully External Project
Projects that rely directly on CMake without Holoscan CLI tooling can use the CMake standard
FetchContent function to fetch and build open-source Holoscan Modules
directly.
# Pre-fill any CMake configuration options for the external module
set(<holoscan_my_sensor_OPTION_1> <value>)
...
include(FetchContent)
FetchContent_Declare(holoscan_my_sensor
GIT_REPOSITORY https://github.com/example/holoscan-my-sensor.git
GIT_TAG 0123456789abcdef0123456789abcdef01234567
)
FetchContent_MakeAvailable(holoscan_my_sensor)
target_link_libraries(my_app PRIVATE holoscan::my_sensor_op)
Building from source may require additional dependency setup and custom configuration options. Please refer to the individual Module's guidance on requirements and best practices. A binary installation is usually a simpler choice for fully external projects, when available.
6. Path C — Consume from a Holoscan Project (CLI Workflow)
As an alternative to writing CMake code yourself, the Holoscan CLI provides a simplified
interface to generate CMake FetchContent strings from CLI standard metadata.json.
If the external module is also aligned to Holoscan CLI, you can simply declare the dependency in your project's metadata and offload manifest generation, discovery, and build commands to Holoscan CLI and CMake.
This approach may be particularly useful for layered, monolithic projects based on Holoscan CLI that have many module dependencies.
6.1 Select a Holoscan project
Work from the root of the repository that consumes the Module. Application examples live in Holoscan Applications. Or, follow Create a Holoscan Module to create a new Holoscan Module project repo from a template.
Follow the consuming project's README to prepare its development environment.
Run holoscan list to see projects in that checkout. The examples below assume an application
named my_app; substitute your project's selector and a Module compatible with its SDK.
6.2 Declare the dependency
Edit your subproject's metadata.json. For an application:
{
"$schema": "urn:holoscan:application:v1",
"application": {
"name": "my_app",
"dependencies": {
"modules": [
{
"name": "holoscan-my-sensor",
"source": {
"git_url": "https://github.com/example/holoscan-my-sensor.git",
"ref": "0123456789abcdef0123456789abcdef01234567"
},
"provides_operators": ["my_sensor_op"]
}
]
}
}
}
This excerpt shows the dependency fields; retain the other required fields in your application's
metadata. Field reference: the module_dependency definition in the Holoscan CLI's
module.schema.json.
name(required) — Module name as published in its ownmetadata.json:module.name.source.{git_url, ref}— the Module's git URL and a pinned 40-character commit SHA. Holoscan CLI requires an immutable SHA. Mutable tags and branches are rejected.provides_operators— operators this dependency contributes. The generated manifest records their provider; the consuming CMake project controls which Modules are fetched and which operators are enabled (OP_<name>=ON), as shown in §6.3.version(optional) — informational; not enforced by the resolver today.
Those metadata details are used by the Holoscan CLI in the next section.
6.3 Build
The consuming project owns its CMake dependency integration. Make the CLI's bundled
HoloHubConfigHelpers.cmake
available under cmake/; generated Modules already include it. In the root CMakeLists.txt,
load the generated manifest and make the required Module available before adding the targets
or subdirectories that use it. For the dependency above:
include(FetchContent)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/HoloHubConfigHelpers.cmake")
include("${CMAKE_BINARY_DIR}/external_operators_manifest.cmake")
set(OP_my_sensor_op ON CACHE BOOL "Build the sensor operator" FORCE)
FetchContent_MakeAvailable(holoscan_my_sensor)
The helper filename and its holohub_declare_external_module() function are the API names
shipped by Holoscan CLI. The provider name holoscan_my_sensor is derived from the
Module name by replacing characters other than letters, digits, and underscores with underscores.
holoscan build my_app --dryrun --verbose
holoscan build my_app
How it works: The Holoscan CLI reads dependencies.modules[] from the selected project's
metadata and writes external_operators_manifest.cmake into its build directory before running
CMake. The manifest declares each Module's source URL and commit. The CMake integration above
fetches the required Module and enables my_sensor_op; link its exported target as shown in §6.5.
Projects using CMake directly can instead declare the source themselves with
Path B.
6.4 Iterate against a local working copy
When iterating against an unreleased Module, the source override is
HOLOSCAN_CLI_LOCAL_<SANITIZED_MODULE_NAME>: replace non-alphanumeric runs in the
dependency's name with underscores, trim leading and trailing underscores, and
uppercase the result. For holoscan-my-sensor, use
HOLOSCAN_CLI_LOCAL_HOLOSCAN_MY_SENSOR.
Holoscan CLI can forward this override by name. Mount the working copy at the path used by the override; forwarding an environment variable does not mount files:
export HOLOSCAN_CLI_LOCAL_HOLOSCAN_MY_SENSOR=/workspace/local-modules/holoscan-my-sensor
holoscan build my_app --dryrun --verbose \
--docker-opts="-v $HOME/repos/holoscan-my-sensor:/workspace/local-modules/holoscan-my-sensor" \
--forward-env HOLOSCAN_CLI_LOCAL_HOLOSCAN_MY_SENSOR
holoscan build my_app \
--docker-opts="-v $HOME/repos/holoscan-my-sensor:/workspace/local-modules/holoscan-my-sensor" \
--forward-env HOLOSCAN_CLI_LOCAL_HOLOSCAN_MY_SENSOR
While the override is set, the resolver uses that working tree instead of
source.ref. For native --local builds, set the variable to the host path.
In CLI 5.0.0, CMake retains FETCHCONTENT_SOURCE_DIR_HOLOSCAN_MY_SENSOR in an existing
build cache after the environment variable is unset. Clear that entry or start from a clean build
when returning to the pinned dependency:
unset HOLOSCAN_CLI_LOCAL_HOLOSCAN_MY_SENSOR
holoscan build my_app --configure-args=-UFETCHCONTENT_SOURCE_DIR_HOLOSCAN_MY_SENSOR --dryrun --verbose
holoscan build my_app --configure-args=-UFETCHCONTENT_SOURCE_DIR_HOLOSCAN_MY_SENSOR
Standalone modules use the same options with holoscan build <app> and can persist the variable
name in tool.holoscan.forward-env; keep machine-specific mount paths on the command line.
6.5 Use the operators in your code
For Python, the Module must also provide Holoscan SDK 5 bindings. A Module generated with
--language cpp python exposes the proxy through holoscan_my_sensor.operators.
Within an existing SDK 5 graph with compatible source and sink ports:
from holoscan_my_sensor.operators import MySensorOp
sensor = MySensorOp(graph, "sensor")
graph.add_flow(source.output, sensor["in"])
graph.add_flow(sensor.out, sink.input)
This is a composition fragment, not a complete application. See the
finite SDK 5 Python example
for the source/sink definitions, graph compilation, and cooperative termination. The module's
Python package must be installed or on PYTHONPATH; fetching its C++ sources alone does not
make Python bindings importable.
C++ application: include the public header the Module installs (path is documented in
its README) and link via the Module's exported targets in your application's
CMakeLists.txt:
target_link_libraries(my_app PRIVATE holoscan::my_sensor_op)
6.6 Discover what's available
holoscan list # Lists projects in this checkout
holoscan list --json
holoscan status --json
holoscan env-check --json
The list is a local project inventory; visit the
Holoscan Ecosystem website to discover
published projects. JSON output includes schema_version: 1. env-check can
exit nonzero when dependencies are missing.
6.7 Module-to-module (transitive) dependencies
If you are building a Holoscan Module that itself depends on another Module, declare it in
module.dependencies[] in the module's metadata.json. It follows the same dependency schema
as application.dependencies.modules[] in §6.2.
Note: CLI 5.0.0 does not merge Module-root dependencies into a selected application's
manifest. With only the Module-root declaration, the manifest is empty and CMake reports
No content details recorded. Also declare the dependency in the selected application's
application.dependencies.modules[] and keep both declarations consistent. See §6.3 for the
CMake integration and §6.4 for mounted-source iteration.
From a standalone module, we recommend using a uv environment with Python >=3.12:
uv run holoscan list --json
uv run holoscan build my_sensor_pipeline --dryrun --verbose
uv run holoscan build my_sensor_pipeline
For the pip fallback, activate
the module's .venv with source .venv/bin/activate and omit uv run.
Enable the dependency's operators in your build graph, just as in §6.3. To work
from another directory, place --project-root /path/to/module before build.
See Create a Module for installation. For a local
build, select the SDK explicitly with --local-sdk-root /path/to/sdk.
7. Path D — External Python Project (Pip Install)
Use this path only when the Module maintainer publishes a compatible wheel. The SDK 5 CLI template does not build Module wheels, and the fictional sensor package below is not available for installation. For a real published Module, follow its SDK/CUDA and package-index instructions:
pip install holoscan # the SDK matching your CUDA variant
pip install holoscan-my-sensor # the module
Use the import path documented by that Module. For the SDK 5 scaffold's Python bindings, see
section 6.5; SDK 4 Application/compose() examples do
not describe the SDK 5 graph API used by this tutorial.
Version note: Holoscan CLI
5.0.0does not yet support Python wheel packaging with Holoscan SDK5.0.0sources out of the box. Use the pre-built Holoscan SDK wheels distributed via PyPI. Wheel authoring support is planned for a later Holoscan SDK release.
8. Reference Card
| Goal | Where or what |
|---|---|
| Declare a Module dep (Holoscan app) | metadata.json:application.dependencies.modules[] |
| Declare a transitive dep (Module → Module) | metadata.json:module.dependencies[] |
| External Module reference | Include source.{git_url, ref} (40-char SHA) and provides_operators |
| Local override | HOLOSCAN_CLI_LOCAL_<SANITIZED_MODULE_NAME>=<container-path> env var |
| Build a Holoscan project with deps | holoscan build <app> |
| Install binary (C++) | apt install holoscan-<name> |
| Install binary (Python) | pip install holoscan-<name> |
| Use from C++ | find_package(holoscan-<name> REQUIRED) + target_link_libraries(... holoscan::<target>) |
| Use generated SDK 5 bindings from Python | from holoscan_my_module.operators import MyOp (requires bindings on PYTHONPATH) |
| Use CLI-declared sources (Path C) | Include the generated manifest and call FetchContent_MakeAvailable(...) in the consuming CMake project |
| Embed via source — fully external (Path B) | FetchContent_Declare(...) + FetchContent_MakeAvailable(...) |
| Inspect a standalone Module | holoscan --project-root /path/to/module list --json |
| Discover published Holoscan Modules | HoloHub Modules catalog |
9. Troubleshooting
find_package(holoscan-my-sensor)fails. Confirm install:dpkg -L holoscan-my-sensor | grep cmake. Add the prefix toCMAKE_PREFIX_PATHif it is not in a standard location.- The Module's Python import raises
ModuleNotFoundError. For generated SDK 5 bindings, usefrom holoscan_my_sensor.operators import MySensorOpand put the built or installed bindings onPYTHONPATH. The generated DEB contains C++ artifacts only. If a maintainer supplies a wheel, verify it and the compatible SDK wheel are installed in the same environment. - Resolver rejects a ref that is not a 40-character commit SHA. Replace the tag or branch
in
source.refwith the commit SHA it resolves to. HOLOSCAN_CLI_LOCAL_*override has no effect. Derive the suffix from the dependencynameas described in §6.4, mount the Module into the project container, and set the variable there to the container path. Add--forward-env HOLOSCAN_CLI_LOCAL_<NAME>to forward the export; the variable must contain the mounted container path.- The operator is not built even though you declared it. Under FetchContent +
PROJECT_IS_TOP_LEVELdefaults, the Module'sBUILD_ALLisOFF, so only the operators marked withOP_<op>=ONget built. In either source-build path (B or C), pass-DOP_<op>=ONon the configure line orset(...)it beforeFetchContent_MakeAvailable. - CMake fails with "No content details recorded" inside
FetchContent_MakeAvailable. Inspectexternal_operators_manifest.cmakein the selected application's build directory. Confirm the dependency is declared on that application (see §6.7), the manifest declares the expected provider, and the rootCMakeLists.txtincludes it beforeFetchContent_MakeAvailable. Re-runholoscan build <app>after correcting the metadata.
10. Next Steps
For the full Holoscan CLI reference, visit the Holoscan CLI repository.
Happy holocoding!