diff --git a/source/Concepts/Intermediate/About-Composition.rst b/source/Concepts/Intermediate/About-Composition.rst
index 4a6a9399ee3..a6cbdb5dcc1 100644
--- a/source/Concepts/Intermediate/About-Composition.rst
+++ b/source/Concepts/Intermediate/About-Composition.rst
@@ -54,6 +54,8 @@ Additionally, once a component is created, it must be registered with the index
# To register multiple components in the same shared library, use multiple calls
# rclcpp_components_register_nodes(talker_component "composition::Talker2")
+For an example, :doc:`check out this tutorial <../../Tutorials/Intermediate/Writing-a-Composable-Node>`
+
.. note::
In order for the component_container to be able to find desired components, it must be executed or launched from a shell that has sourced the corresponding workspace.
diff --git a/source/Releases/Release-Dashing-Diademata.rst b/source/Releases/Release-Dashing-Diademata.rst
index 1b715590163..9a26bb7699e 100644
--- a/source/Releases/Release-Dashing-Diademata.rst
+++ b/source/Releases/Release-Dashing-Diademata.rst
@@ -499,7 +499,7 @@ If not present, registration macros must be added to the project's CMake.
add_library(listener src/listener.cpp)
rclcpp_components_register_nodes(listener "composition::Listener")
-For more information on composition, see `the tutorial `__
+For more information on composition, see `the tutorial <../Tutorials/Intermediate/Writing-a-Composable-Node>`
rclpy
^^^^^
diff --git a/source/Tutorials/Intermediate.rst b/source/Tutorials/Intermediate.rst
index aba392c653e..ce416511732 100644
--- a/source/Tutorials/Intermediate.rst
+++ b/source/Tutorials/Intermediate.rst
@@ -8,6 +8,7 @@ Intermediate
Intermediate/Creating-an-Action
Intermediate/Writing-an-Action-Server-Client/Cpp
Intermediate/Writing-an-Action-Server-Client/Py
+ Intermediate/Writing-a-Composable-Node
Intermediate/Composition
Intermediate/Monitoring-For-Parameter-Changes-CPP
Intermediate/Monitoring-For-Parameter-Changes-Python
diff --git a/source/Tutorials/Intermediate/Composition.rst b/source/Tutorials/Intermediate/Composition.rst
index b36933da647..45b4120b74f 100644
--- a/source/Tutorials/Intermediate/Composition.rst
+++ b/source/Tutorials/Intermediate/Composition.rst
@@ -21,6 +21,8 @@ Background
See the :doc:`conceptual article <../../Concepts/Intermediate/About-Composition>`.
+For information on how to write a composable node, :doc:`check out this tutorial `.
+
Run the demos
-------------
diff --git a/source/Tutorials/Intermediate/Writing-a-Composable-Node.rst b/source/Tutorials/Intermediate/Writing-a-Composable-Node.rst
new file mode 100644
index 00000000000..9f559aa2444
--- /dev/null
+++ b/source/Tutorials/Intermediate/Writing-a-Composable-Node.rst
@@ -0,0 +1,170 @@
+Writing a Composable Node (C++)
+===============================
+
+.. contents:: Table of Contents
+ :depth: 2
+ :local:
+
+Starting Place
+--------------
+
+Let's assume that you have a regular ``rclcpp::Node`` executable that you want to run in the same process as other nodes to enable more efficient communication.
+
+We'll start from having a class that directly inherits from ``Node``, and that also has a main method defined.
+
+.. code-block:: c++
+
+ namespace palomino
+ {
+ class VincentDriver : public rclcpp::Node
+ {
+ // ...
+ };
+ }
+
+ int main(int argc, char * argv[])
+ {
+ rclcpp::init(argc, argv);
+ rclcpp::spin(std::make_shared());
+ rclcpp::shutdown();
+ return 0;
+ }
+
+This will typically be compiled as an executable in your Cmake.
+
+.. code-block:: cmake
+
+ # ...
+ add_executable(vincent_driver src/vincent_driver.cpp)
+ # ...
+ install(TARGETS vincent_driver
+ DESTINATION lib/${PROJECT_NAME}
+ )
+
+Code Updates
+------------
+
+Add the Package Dependency
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Your `package.xml `__ should have a dependency on ``rclcpp_components``, a la
+
+.. code-block:: xml
+
+ rclcpp_components
+
+Alternatively, you can independently add a ``build_depend/exec_depend``.
+
+Class Definition
+^^^^^^^^^^^^^^^^
+
+The only change to your class definition that you may have to do is ensure that `the constructor for the class `__ takes a ``NodeOptions`` argument.
+
+.. code-block:: c++
+
+ VincentDriver(const rclcpp::NodeOptions & options) : Node("vincent_driver", options)
+ {
+ // ...
+ }
+
+No More Main Method
+^^^^^^^^^^^^^^^^^^^
+
+Replace your main method with a ``pluginlib``-style macro invocation.
+
+.. code-block:: c++
+
+ #include
+ RCLCPP_COMPONENTS_REGISTER_NODE(palomino::VincentDriver)
+
+.. caution::
+ If the main method you are replacing contains a ``MultiThreadedExecutor``, be sure to make note and ensure that your container node is multithreaded.
+ See section below.
+
+CMake Changes
+^^^^^^^^^^^^^
+First, add ``rclcpp_components`` as a dependency in your CMakeLists.txt with:
+
+.. code-block:: cmake
+
+ find_package(rclcpp_components REQUIRED)
+
+Second, we're going to replace our ``add_executable`` with a ``add_library`` with a new target name.
+
+.. code-block:: cmake
+
+ add_library(vincent_driver_component src/vincent_driver.cpp)
+
+Third, replace other build commands that used the old target to act on the new target.
+i.e. ``ament_target_dependencies(vincent_driver ...)`` becomes ``ament_target_dependencies(vincent_driver_component ...)``
+
+Fourth, add a new command to declare your component.
+
+.. code-block:: cmake
+
+ rclcpp_components_register_node(
+ vincent_driver_component
+ PLUGIN "palomino::VincentDriver"
+ EXECUTABLE vincent_driver
+ )
+
+Fifth and finally, change any installation commands in the CMake that operated on the old target to install the library version instead.
+For instance, do not install either target into ``lib/${PROJECT_NAME}``.
+Replace with the library installation.
+
+.. code-block:: cmake
+
+ ament_export_targets(export_vincent_driver_component)
+ install(TARGETS vincent_driver_component
+ EXPORT export_vincent_driver_component
+ ARCHIVE DESTINATION lib
+ LIBRARY DESTINATION lib
+ RUNTIME DESTINATION bin
+ )
+
+
+Running Your Node
+-----------------
+
+See the :doc:`Composition tutorial ` for an in-depth look at composing nodes.
+The quick and dirty version is that if you had the following in your Python launch file,
+
+.. code-block:: python
+
+ from launch_ros.actions import Node
+
+ # ..
+
+ ld.add_action(Node(
+ package='palomino',
+ executable='vincent_driver',
+ # ..
+ ))
+
+you can replace it with
+
+.. code-block:: python
+
+ from launch_ros.actions import ComposableNodeContainer
+ from launch_ros.descriptions import ComposableNode
+
+ # ..
+ ld.add_action(ComposableNodeContainer(
+ name='a_buncha_nodes',
+ namespace='',
+ package='rclcpp_components',
+ executable='component_container',
+ composable_node_descriptions=[
+ ComposableNode(
+ package='palomino',
+ plugin='palomino::VincentDriver',
+ name='vincent_driver',
+ # ..
+ extra_arguments=[{'use_intra_process_comms': True}],
+ ),
+ ]
+ ))
+
+.. caution::
+
+ If you need multi-threading, instead of setting your executable to ``component_container``, set it to ``component_container_mt``