Start using unique_ptr
diff --git a/include/rive/artboard.hpp b/include/rive/artboard.hpp
index e9a32d8..5a8aa2f 100644
--- a/include/rive/artboard.hpp
+++ b/include/rive/artboard.hpp
@@ -132,7 +132,7 @@
 
         /// Make an instance of this artboard, must be explictly deleted when no
         /// longer needed.
-        Artboard* instance() const;
+        std::unique_ptr<Artboard> instance() const;
 
         /// Returns true if the artboard is an instance of another
         bool isInstance() const { return m_IsInstance; }
diff --git a/include/rive/file.hpp b/include/rive/file.hpp
index b1ca2a5..b11ef0e 100644
--- a/include/rive/file.hpp
+++ b/include/rive/file.hpp
@@ -37,11 +37,11 @@
     private:
         /// The file's backboard. All Rive files have a single backboard
         /// where the artboards live.
-        Backboard* m_Backboard = nullptr;
+        std::unique_ptr<Backboard> m_Backboard;
 
         /// List of artboards in the file. Each artboard encapsulates a set of
         /// Rive components and animations.
-        std::vector<Artboard*> m_Artboards;
+        std::vector<std::unique_ptr<Artboard>> m_Artboards;
 
         /// The helper used to resolve assets when they're not provided in-band
         /// with the file.
@@ -65,7 +65,7 @@
                                    FileAssetResolver* assetResolver = nullptr);
 
         /// @returns the file's backboard. All files have exactly one backboard.
-        Backboard* backboard() const;
+        Backboard* backboard() const { return m_Backboard.get(); }
 
         /// @returns the default artboard. This is typically the first artboard
         /// found in the file's artboard list.
diff --git a/skia/viewer/src/main.cpp b/skia/viewer/src/main.cpp
index 6ce3d05..1ff6fbb 100644
--- a/skia/viewer/src/main.cpp
+++ b/skia/viewer/src/main.cpp
@@ -32,8 +32,8 @@
 #include <stdio.h>
 
 std::string filename;
-rive::File* currentFile = nullptr;
-rive::Artboard* artboard = nullptr;
+std::unique_ptr<rive::File> currentFile;
+std::unique_ptr<rive::Artboard> artboard;
 rive::StateMachineInstance* stateMachineInstance = nullptr;
 rive::LinearAnimationInstance* animationInstance = nullptr;
 uint8_t* fileBytes = nullptr;
@@ -54,15 +54,11 @@
         fprintf(stderr, "failed to import file\n");
         return;
     }
-    auto sourceArtboard = file->artboard();
-    // Artboard should always be instance and hence must be deleted.
-    delete artboard;
-    artboard = sourceArtboard->instance();
+    artboard = file->artboard()->instance();
     artboard->advance(0.0f);
 
     delete animationInstance;
     delete stateMachineInstance;
-    delete currentFile;
     animationInstance = nullptr;
     stateMachineInstance = nullptr;
 
@@ -73,7 +69,7 @@
         stateMachineInstance = new rive::StateMachineInstance(stateMachine);
     }
 
-    currentFile = file;
+    currentFile.reset(file);
 }
 
 void initAnimation(int index) {
@@ -88,15 +84,11 @@
         fprintf(stderr, "failed to import file\n");
         return;
     }
-    auto sourceArtboard = file->artboard();
-    // Artboard should always be instance and hence must be deleted.
-    delete artboard;
-    artboard = sourceArtboard->instance();
+    artboard = file->artboard()->instance();
     artboard->advance(0.0f);
 
     delete animationInstance;
     delete stateMachineInstance;
-    delete currentFile;
     animationInstance = nullptr;
     stateMachineInstance = nullptr;
 
@@ -106,7 +98,7 @@
         animationInstance = new rive::LinearAnimationInstance(animation);
     }
 
-    currentFile = file;
+    currentFile.reset(file);
 }
 
 void glfwErrorCallback(int error, const char* description) { puts(description); }
@@ -287,9 +279,9 @@
         if (artboard != nullptr) {
             if (animationInstance != nullptr) {
                 animationInstance->advance(elapsed);
-                animationInstance->apply(artboard);
+                animationInstance->apply(artboard.get());
             } else if (stateMachineInstance != nullptr) {
-                stateMachineInstance->advance(artboard, elapsed);
+                stateMachineInstance->advance(artboard.get(), elapsed);
             }
             artboard->advance(elapsed);
 
@@ -300,7 +292,7 @@
                            rive::AABB(0, 0, width, height),
                            artboard->bounds());
 
-            post_mouse_event(artboard, canvas->getTotalMatrix());
+            post_mouse_event(artboard.get(), canvas->getTotalMatrix());
 
             artboard->draw(&renderer);
             renderer.restore();
@@ -322,7 +314,7 @@
                         *name = animationName;
                         return true;
                     },
-                    artboard,
+                    artboard.get(),
                     artboard->animationCount(),
                     4))
             {
@@ -337,7 +329,7 @@
                         *name = machineName;
                         return true;
                     },
-                    artboard,
+                    artboard.get(),
                     artboard->stateMachineCount(),
                     4))
             {
@@ -393,7 +385,7 @@
             }
             ImGui::End();
             
-            test_messages(artboard);
+            test_messages(artboard.get());
         } else {
             ImGui::Text("Drop a .riv file to preview.");
         }
@@ -405,7 +397,6 @@
         glfwPollEvents();
     }
 
-    delete currentFile;
     delete[] fileBytes;
 
     // Cleanup Skia.
diff --git a/src/artboard.cpp b/src/artboard.cpp
index d9cb7cb..d44e43a 100644
--- a/src/artboard.cpp
+++ b/src/artboard.cpp
@@ -490,12 +490,12 @@
     return m_StateMachines[index];
 }
 
-Artboard* Artboard::instance() const {
-    auto artboardClone = clone()->as<Artboard>();
+std::unique_ptr<Artboard> Artboard::instance() const {
+    std::unique_ptr<Artboard> artboardClone(clone()->as<Artboard>());
     artboardClone->m_FrameOrigin = m_FrameOrigin;
 
     std::vector<Core*>& cloneObjects = artboardClone->m_Objects;
-    cloneObjects.push_back(artboardClone);
+    cloneObjects.push_back(artboardClone.get());
 
     // Skip first object (artboard).
     auto itr = m_Objects.begin();
@@ -512,7 +512,6 @@
     }
 
     if (artboardClone->initialize() != StatusCode::Ok) {
-        delete artboardClone;
         artboardClone = nullptr;
     } else {
         artboardClone->m_IsInstance = true;
diff --git a/src/file.cpp b/src/file.cpp
index 3f1de50..f83d658 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -108,12 +108,7 @@
 
 File::File(FileAssetResolver* assetResolver) : m_AssetResolver(assetResolver) {}
 
-File::~File() {
-    for (auto artboard : m_Artboards) {
-        delete artboard;
-    }
-    delete m_Backboard;
-}
+File::~File() {}
 
 // Import a Rive file from a file handle
 ImportResult
@@ -153,10 +148,10 @@
         if (object->import(importStack) == StatusCode::Ok) {
             switch (object->coreType()) {
                 case Backboard::typeKey:
-                    m_Backboard = object->as<Backboard>();
+                    m_Backboard.reset(object->as<Backboard>());
                     break;
                 case Artboard::typeKey:
-                    m_Artboards.push_back(object->as<Artboard>());
+                    m_Artboards.push_back(std::unique_ptr<Artboard>(object->as<Artboard>()));
                     break;
             }
         } else {
@@ -233,12 +228,10 @@
                                                    : ImportResult::malformed;
 }
 
-Backboard* File::backboard() const { return m_Backboard; }
-
 Artboard* File::artboard(std::string name) const {
-    for (auto artboard : m_Artboards) {
+    for (const auto& artboard : m_Artboards) {
         if (artboard->name() == name) {
-            return artboard;
+            return artboard.get();
         }
     }
     return nullptr;
@@ -248,12 +241,12 @@
     if (m_Artboards.empty()) {
         return nullptr;
     }
-    return m_Artboards[0];
+    return m_Artboards[0].get();
 }
 
 Artboard* File::artboard(size_t index) const {
     if (index >= m_Artboards.size()) {
         return nullptr;
     }
-    return m_Artboards[index];
+    return m_Artboards[index].get();
 }
diff --git a/src/nested_artboard.cpp b/src/nested_artboard.cpp
index adae05a..f5d6253 100644
--- a/src/nested_artboard.cpp
+++ b/src/nested_artboard.cpp
@@ -17,7 +17,9 @@
     if (m_NestedInstance == nullptr) {
         return nestedArtboard;
     }
-    nestedArtboard->nest(m_NestedInstance->instance());
+    auto ni = m_NestedInstance->instance();
+    assert(ni->isInstance());
+    nestedArtboard->nest(ni.release());
     return nestedArtboard;
 }
 
diff --git a/test/image_mesh_test.cpp b/test/image_mesh_test.cpp
index 6b2c29c..d1575f2 100644
--- a/test/image_mesh_test.cpp
+++ b/test/image_mesh_test.cpp
@@ -62,8 +62,4 @@
     // Important part, make sure they're all actually the same reference.
     REQUIRE(tape1->mesh()->indices() == tape2->mesh()->indices());
     REQUIRE(tape2->mesh()->indices() == tape3->mesh()->indices());
-
-    delete instance1;
-    delete instance2;
-    delete instance3;
 }
diff --git a/test/instancing_test.cpp b/test/instancing_test.cpp
index c237798..25493b3 100644
--- a/test/instancing_test.cpp
+++ b/test/instancing_test.cpp
@@ -74,8 +74,6 @@
     rive::NoOpRenderer renderer;
     artboard->draw(&renderer);
 
-    delete artboard;
-
     delete file;
     delete[] bytes;
 }
@@ -103,7 +101,6 @@
     REQUIRE(file->artboard()->firstAnimation() == artboard->firstAnimation());
 
     rive::LinearAnimation::deleteCount = 0;
-    delete artboard;
     // Make sure no animations were deleted by deleting the instance.
     REQUIRE(rive::LinearAnimation::deleteCount == 0);