Use unique_ptr when we know we have to manage its lifetime
diff --git a/include/rive/artboard.hpp b/include/rive/artboard.hpp
index 6a42bf1..1d9a53a 100644
--- a/include/rive/artboard.hpp
+++ b/include/rive/artboard.hpp
@@ -33,8 +33,8 @@
         std::vector<NestedArtboard*> m_NestedArtboards;
 
         unsigned int m_DirtDepth = 0;
-        CommandPath* m_BackgroundPath = nullptr;
-        CommandPath* m_ClipPath = nullptr;
+        std::unique_ptr<CommandPath> m_BackgroundPath;
+        std::unique_ptr<CommandPath> m_ClipPath;
         Drawable* m_FirstDrawable = nullptr;
         bool m_IsInstance = false;
         bool m_FrameOrigin = true;
@@ -72,8 +72,8 @@
         };
         void draw(Renderer* renderer, DrawOption = DrawOption::kNormal);
 
-        CommandPath* clipPath() const { return m_ClipPath; }
-        CommandPath* backgroundPath() const { return m_BackgroundPath; }
+        CommandPath* clipPath() const { return m_ClipPath.get(); }
+        CommandPath* backgroundPath() const { return m_BackgroundPath.get(); }
 
         const std::vector<Core*>& objects() const { return m_Objects; }
 
diff --git a/include/rive/rive_types.hpp b/include/rive/rive_types.hpp
index 3606b51..0f25495 100644
--- a/include/rive/rive_types.hpp
+++ b/include/rive/rive_types.hpp
@@ -37,6 +37,7 @@
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
+#include <memory>
 #include <type_traits>
 
 #endif  // rive_types
diff --git a/include/rive/shapes/path.hpp b/include/rive/shapes/path.hpp
index 73ffdca..c20e213 100644
--- a/include/rive/shapes/path.hpp
+++ b/include/rive/shapes/path.hpp
@@ -1,12 +1,12 @@
 #ifndef _RIVE_PATH_HPP_
 #define _RIVE_PATH_HPP_
+#include "rive/command_path.hpp"
 #include "rive/generated/shapes/path_base.hpp"
 #include "rive/math/mat2d.hpp"
 #include <vector>
 
 namespace rive {
     class Shape;
-    class CommandPath;
     class PathVertex;
 
 #ifdef ENABLE_QUERY_FLAT_VERTICES
@@ -33,16 +33,15 @@
     class Path : public PathBase {
     protected:
         Shape* m_Shape = nullptr;
-        CommandPath* m_CommandPath = nullptr;
+        std::unique_ptr<CommandPath> m_CommandPath;
         std::vector<PathVertex*> m_Vertices;
 
     public:
-        ~Path();
         Shape* shape() const { return m_Shape; }
         StatusCode onAddedClean(CoreContext* context) override;
         void buildDependencies() override;
         virtual const Mat2D& pathTransform() const;
-        CommandPath* commandPath() const { return m_CommandPath; }
+        CommandPath* commandPath() const { return m_CommandPath.get(); }
         void update(ComponentDirt value) override;
 
         void addVertex(PathVertex* vertex);
@@ -60,4 +59,4 @@
     };
 } // namespace rive
 
-#endif
\ No newline at end of file
+#endif
diff --git a/include/rive/shapes/path_composer.hpp b/include/rive/shapes/path_composer.hpp
index fb27068..ea67d86 100644
--- a/include/rive/shapes/path_composer.hpp
+++ b/include/rive/shapes/path_composer.hpp
@@ -8,18 +8,17 @@
     class PathComposer : public Component {
     private:
         Shape* m_Shape;
-        CommandPath* m_LocalPath = nullptr;
-        CommandPath* m_WorldPath = nullptr;
+        std::unique_ptr<CommandPath> m_LocalPath;
+        std::unique_ptr<CommandPath> m_WorldPath;
 
     public:
         PathComposer(Shape* shape);
-        ~PathComposer();
         Shape* shape() const { return m_Shape; }
         void buildDependencies() override;
         void update(ComponentDirt value) override;
 
-        CommandPath* localPath() const { return m_LocalPath; }
-        CommandPath* worldPath() const { return m_WorldPath; }
+        CommandPath* localPath() const { return m_LocalPath.get(); }
+        CommandPath* worldPath() const { return m_WorldPath.get(); }
     };
 } // namespace rive
-#endif
\ No newline at end of file
+#endif
diff --git a/include/rive/shapes/shape_paint_container.hpp b/include/rive/shapes/shape_paint_container.hpp
index 56b3b5f..1f1eede 100644
--- a/include/rive/shapes/shape_paint_container.hpp
+++ b/include/rive/shapes/shape_paint_container.hpp
@@ -26,8 +26,8 @@
 
         void invalidateStrokeEffects();
 
-        CommandPath* makeCommandPath(PathSpace space);
+        std::unique_ptr<CommandPath> makeCommandPath(PathSpace space);
     };
 } // namespace rive
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/artboard.cpp b/src/artboard.cpp
index f358abc..b7b8ed6 100644
--- a/src/artboard.cpp
+++ b/src/artboard.cpp
@@ -37,9 +37,6 @@
             delete object;
         }
     }
-
-    delete m_ClipPath;
-    delete m_BackgroundPath;
 }
 
 static bool canContinue(StatusCode code) {
@@ -382,7 +379,7 @@
 
     if (option != DrawOption::kHideBG) {
         for (auto shapePaint : m_ShapePaints) {
-            shapePaint->draw(renderer, m_BackgroundPath);
+            shapePaint->draw(renderer, backgroundPath());
         }
     }
 
diff --git a/src/shapes/path.cpp b/src/shapes/path.cpp
index 4f877a4..c07803f 100644
--- a/src/shapes/path.cpp
+++ b/src/shapes/path.cpp
@@ -10,8 +10,6 @@
 
 using namespace rive;
 
-Path::~Path() { delete m_CommandPath; }
-
 StatusCode Path::onAddedClean(CoreContext* context) {
     StatusCode code = Super::onAddedClean(context);
     if (code != StatusCode::Ok) {
diff --git a/src/shapes/path_composer.cpp b/src/shapes/path_composer.cpp
index fbfdf28..ff843d6 100644
--- a/src/shapes/path_composer.cpp
+++ b/src/shapes/path_composer.cpp
@@ -9,10 +9,6 @@
 static Mat2D identity;
 
 PathComposer::PathComposer(Shape* shape) : m_Shape(shape) {}
-PathComposer::~PathComposer() {
-    delete m_LocalPath;
-    delete m_WorldPath;
-}
 
 void PathComposer::buildDependencies() {
     assert(m_Shape != nullptr);
diff --git a/src/shapes/shape_paint_container.cpp b/src/shapes/shape_paint_container.cpp
index d90f059..bdd5356 100644
--- a/src/shapes/shape_paint_container.cpp
+++ b/src/shapes/shape_paint_container.cpp
@@ -40,7 +40,7 @@
     }
 }
 
-CommandPath* ShapePaintContainer::makeCommandPath(PathSpace space) {
+std::unique_ptr<CommandPath> ShapePaintContainer::makeCommandPath(PathSpace space) {
     // Force a render path if we specifically request to use it for clipping or
     // this shape is used for clipping.
     bool needForRender = ((space | m_DefaultPathSpace) & PathSpace::Clipping) ==
@@ -62,10 +62,10 @@
     }
 
     if (needForEffects && needForRender) {
-        return new RenderMetricsPath();
+        return std::unique_ptr<CommandPath>(new RenderMetricsPath());
     } else if (needForEffects) {
-        return new OnlyMetricsPath();
+        return std::unique_ptr<CommandPath>(new OnlyMetricsPath());
     } else {
-        return rive::makeRenderPath();
+        return std::unique_ptr<CommandPath>(rive::makeRenderPath());
     }
-}
\ No newline at end of file
+}