> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/holoscan/sdk-user-guide/llms.txt.
> For full documentation content, see https://docs.nvidia.com/holoscan/sdk-user-guide/llms-full.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/holoscan/sdk-user-guide/_mcp/server.

In this example, we extend the previous [video replayer application](/holoscan/sdk-user-guide/using-the-sdk/holoscan-by-example/video-replayer) into a multi-node [distributed application](/holoscan/sdk-user-guide/using-the-sdk/create-a-distributed-application). A distributed application is made up of multiple Fragments (C++ (`holoscan::Fragment`)/Python (`holoscan.core.Fragment`)), each of which may run on its own node.

In the distributed case we will:

* Create one fragment that loads a video file from disk using **VideoStreamReplayerOp** operator.
* Create a second fragment that will display the video using the **HolovizOp** operator.

These two fragments will be combined into a distributed application such that the display of the video frames could occur on a separate node from the node where the data is read.

The example source code and run instructions can be found in the [examples](https://github.com/nvidia-holoscan/holoscan-sdk/blob/main/examples#holoscan-sdk-examples) directory on GitHub, or under `/opt/nvidia/holoscan/examples` in the NGC container and the Debian package, alongside their executables.

## Operators and Workflow

Here is the diagram of the operators and workflow used in this example.

![Workflow to load and display video from a file](https://kroki.io/graphviz/svg/eNpVjUEKwjAQRfc5xZCVLuwBlLp2IQhV3JRSUjPYwTQJk7Sg1rsbUYuuhs_895-mMyvfwkAaXc3ojboi15pCZGr6iBrugpW9aOJcbgsprNMIZWiVx5zx5FhXKyG-JJRGNWhyeXwN7iOj6orPb-dHGF0ffR9n6cxhCQe0wbFMCwPdJnbjjEs59UuyVZIgDchh6sMI8k-6WMMv_3ZkWTahshIP8QQK7VSC)

This is the same workflow as the [single fragment video replayer](/holoscan/sdk-user-guide/using-the-sdk/holoscan-by-example/video-replayer). Each operator is assigned to a separate fragment and there is now a network connection between the fragments.

## Defining and Connecting Fragments

Distributed applications define fragments explicitly to isolate the different units of work that could be distributed to different nodes. In this example:

* We define two classes that inherit from `Fragment`:
  * **Fragment1** contains an instance of **VideoStreamReplayerOp** named "replayer."
  * **Fragment2** contains an instance of **HolovizOp** name "holoviz."
* We create an application, **DistributedVideoReplayerApp**. In its compose method:
  * we call **make\_fragment** to initialize both fragments.
  * we then connect the "output" port of "replayer" operator in fragment1 to the "receivers" port of the "holoviz" operator in fragment2 to define the application workflow.
* The operators instantiated in the fragments can still be configured with parameters initialized from the YAML configuration ingested by the application using `holoscan::Fragment::from_config` (C++) or `holoscan.core.Fragment.kwargs` (Python).

```cpp
  #include &lt;holoscan/holoscan.hpp&gt;
  #include &lt;holoscan/operators/holoviz/holoviz.hpp&gt;
  #include &lt;holoscan/operators/video_stream_replayer/video_stream_replayer.hpp&gt;
   
  class Fragment1 : public holoscan::Fragment {
   public:
    void compose() override {
      using namespace holoscan;
   
      auto replayer = make_operator&lt;ops::VideoStreamReplayerOp&gt;("replayer", from_config("replayer"));
      add_operator(replayer);
    }
  };
   
  class Fragment2 : public holoscan::Fragment {
   public:
    void compose() override {
      using namespace holoscan;
   
      auto visualizer = make_operator&lt;ops::HolovizOp&gt;("holoviz", from_config("holoviz"));
      add_operator(visualizer);
    }
  };
   
  class DistributedVideoReplayerApp : public holoscan::Application {
   public:
    void compose() override {
      using namespace holoscan;
   
      auto fragment1 = make_fragment<Fragment1>("fragment1");
      auto fragment2 = make_fragment<Fragment2>("fragment2");
   
      // Define the workflow: replayer -> holoviz
      add_flow(fragment1, fragment2, {{"replayer.output", "holoviz.receivers"}});
    }
  };
   
  int main(int argc, char** argv) {
    // Get the yaml configuration file
    auto config_path = std::filesystem::canonical(argv[0]).parent_path();
    config_path /= std::filesystem::path("video_replayer_distributed.yaml");
   
    auto app = holoscan::make_application<DistributedVideoReplayerApp>();
    app->config(config_path);
    app->run();
   
    return 0;
  }
```

```python
  import os
   
  from holoscan.core import Application, Fragment
  from holoscan.operators import HolovizOp, VideoStreamReplayerOp
   
  sample_data_path = os.environ.get("HOLOSCAN_INPUT_PATH", "../data")
   
   
  class Fragment1(Fragment):
      def __init__(self, app, name):
          super().__init__(app, name)
   
      def compose(self):
          # Set the video source
          video_path = self._get_input_path()
          logging.info(
              f"Using video from {video_path}"
          )
   
          # Define the replayer and holoviz operators
          replayer = VideoStreamReplayerOp(
              self, name="replayer", directory=video_path, **self.kwargs("replayer")
          )
   
          self.add_operator(replayer)
   
      def _get_input_path(self):
          path = os.environ.get(
              "HOLOSCAN_INPUT_PATH", os.path.join(os.path.dirname(__file__), "data")
          )
          return os.path.join(path, "racerx")
   
   
  class Fragment2(Fragment):
      def compose(self):
          visualizer = HolovizOp(self, name="holoviz", **self.kwargs("holoviz"))
   
          self.add_operator(visualizer)
   
   
  class DistributedVideoReplayerApp(Application):
      """Example of a distributed application that uses the fragments and operators defined above.
   
      This application has the following fragments:
      - Fragment1
        - holding VideoStreamReplayerOp
      - Fragment2
        - holding HolovizOp
   
      The VideoStreamReplayerOp reads a video file and sends the frames to the HolovizOp.
      The HolovizOp displays the frames.
      """
   
      def compose(self):
          # Define the fragments
          fragment1 = Fragment1(self, name="fragment1")
          fragment2 = Fragment2(self, name="fragment2")
   
          # Define the workflow
          self.add_flow(fragment1, fragment2, {("replayer.output", "holoviz.receivers")})
   
   
  def main():
      config_file_path = os.path.join(os.path.dirname(__file__), "video_replayer_distributed.yaml")
   
      logging.info(f"Reading application configuration from {config_file_path}")
   
      app = DistributedVideoReplayerApp()
      app.config(config_file_path)
      app.run()
   
   
  if __name__ == "__main__":
      main()
```

This particular distributed application only has one operator per fragment, so the operators were added via **`add_operator` (C++ (`holoscan::Fragment::add_operator`)/Python (`holoscan.core.Fragment.add_operator`))**. In general, each fragment may have multiple operators and connections between operators within a fragment would be made using `add_flow()` (C++ (`holoscan::Fragment::add_flow`)/Python (`holoscan.core.Fragment.add_flow`)) method within the fragment's `compute()` (C++ (`holoscan::Operator::compute`)/Python (`holoscan.core.Operator.compute`)) method.

## Running the Application

Running the application should bring up video playback of the video referenced in the YAML file.

![](https://files.buildwithfern.com/nvidia-holoscan.docs.buildwithfern.com/holoscan/sdk-user-guide/c6ad083203e0a510d84f9b625a9c198f5a9accfdc3a29c3d149ff08a90ba046c/docs/images/video_replayer.png)

Instructions for running the distributed application involve calling the application from the "driver" node as well as from any worker nodes. For details, see the application run instructions in the [examples](https://github.com/nvidia-holoscan/holoscan-sdk/blob/main/examples/video_replayer_distributed) directory on GitHub, or under `/opt/nvidia/holoscan/examples/video_replayer_distributed` in the NGC container and the Debian package.

Refer to [UCX Network Interface Selection](/holoscan/sdk-user-guide/using-the-sdk/create-a-distributed-application#ucx-network-selection) when running a distributed application across multiple nodes.