diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 24fa92cee527f676aa6d1fd7200c2276374db109..7702ccb650e7994cb37ae628d860abbb9d546a94 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -318,6 +318,14 @@ namespace vkcv
 		
 		void recordBlitImage(const CommandStreamHandle& cmdStream, const ImageHandle& src, const ImageHandle& dst,
 							 SamplerFilterType filterType);
+	
+		void setDebugLabel(const BufferHandle &handle, const std::string &label);
+		void setDebugLabel(const PassHandle &handle, const std::string &label);
+		void setDebugLabel(const PipelineHandle &handle, const std::string &label);
+		void setDebugLabel(const DescriptorSetHandle &handle, const std::string &label);
+		void setDebugLabel(const SamplerHandle &handle, const std::string &label);
+		void setDebugLabel(const ImageHandle &handle, const std::string &label);
+		void setDebugLabel(const CommandStreamHandle &handle, const std::string &label);
 		
     };
 }
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index 253efad491e6e320ba5e5e8b270b187e2e79da82..613944481866017a6b58d7fb7c549cbe4b2e7fc7 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -32,6 +32,8 @@ int main(int argc, const char** argv) {
 	uint16_t indices[3] = { 0, 1, 2 };
 	triangleIndexBuffer.fill(&indices[0], sizeof(indices));
 
+	core.setDebugLabel(triangleIndexBuffer.getHandle(), "Triangle Index Buffer");
+	
 	// an example attachment for passes that output to the window
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
@@ -46,6 +48,8 @@ int main(int argc, const char** argv) {
 		std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
 		return EXIT_FAILURE;
 	}
+	
+	core.setDebugLabel(trianglePass, "Triangle Pass");
 
 	vkcv::ShaderProgram triangleShaderProgram;
 	vkcv::shader::GLSLCompiler compiler;
@@ -78,12 +82,15 @@ int main(int argc, const char** argv) {
 		return EXIT_FAILURE;
 	}
 	
+	core.setDebugLabel(trianglePipeline, "Triangle Pipeline");
+	
 	auto start = std::chrono::system_clock::now();
 
 	const vkcv::Mesh renderMesh({}, triangleIndexBuffer.getVulkanHandle(), 3);
 	vkcv::DrawcallInfo drawcall(renderMesh, {},1);
 
 	const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
+	core.setDebugLabel(swapchainInput, "Swapchain Image");
 
     vkcv::camera::CameraManager cameraManager(window);
     uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
@@ -113,6 +120,7 @@ int main(int argc, const char** argv) {
 		pushConstants.appendDrawcall(mvp);
 		
 		auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
+		core.setDebugLabel(cmdStream, "Render Commands");
 
 		core.recordDrawcallsToCmdStream(
 			cmdStream,
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 819b99bd57f33408250af71ca2794b04414e31fa..0b77142628075afdefd4976aa4fc45426086b4b1 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -832,4 +832,141 @@ namespace vkcv
 		}, nullptr);
 	}
 	
+	static void setDebugObjectLabel(const vk::Device& device, const vk::ObjectType& type,
+									uint64_t handle, const std::string& label) {
+#ifndef NDEBUG
+		static PFN_vkSetDebugUtilsObjectNameEXT setDebugLabel = reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(
+				device.getProcAddr("vkSetDebugUtilsObjectNameEXT")
+		);
+		
+		if (!setDebugLabel) {
+			return;
+		}
+		
+		const vk::DebugUtilsObjectNameInfoEXT debug (
+				type,
+				handle,
+				label.c_str()
+		);
+		
+		setDebugLabel(device, &(static_cast<const VkDebugUtilsObjectNameInfoEXT&>(debug)));
+#endif
+	}
+	
+	void Core::setDebugLabel(const BufferHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::eBuffer,
+				reinterpret_cast<uint64_t>(static_cast<VkBuffer>(
+						m_BufferManager->getBuffer(handle)
+				)),
+				label
+		);
+	}
+	
+	void Core::setDebugLabel(const PassHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::eRenderPass,
+				reinterpret_cast<uint64_t>(static_cast<VkRenderPass>(
+						m_PassManager->getVkPass(handle)
+				)),
+				label
+		);
+	}
+	
+	void Core::setDebugLabel(const PipelineHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::ePipeline,
+				reinterpret_cast<uint64_t>(static_cast<VkPipeline>(
+						m_PipelineManager->getVkPipeline(handle)
+				)),
+				label
+		);
+	}
+	
+	void Core::setDebugLabel(const DescriptorSetHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::eDescriptorSet,
+				reinterpret_cast<uint64_t>(static_cast<VkDescriptorSet>(
+						m_DescriptorManager->getDescriptorSet(handle).vulkanHandle
+				)),
+				label
+		);
+	}
+	
+	void Core::setDebugLabel(const SamplerHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::eSampler,
+				reinterpret_cast<uint64_t>(static_cast<VkSampler>(
+						m_SamplerManager->getVulkanSampler(handle)
+				)),
+				label
+		);
+	}
+	
+	void Core::setDebugLabel(const ImageHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		} else
+		if (handle.isSwapchainImage()) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to swapchain image");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::eImage,
+				reinterpret_cast<uint64_t>(static_cast<VkImage>(
+						m_ImageManager->getVulkanImage(handle)
+				)),
+				label
+		);
+	}
+	
+	void Core::setDebugLabel(const CommandStreamHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::eCommandBuffer,
+				reinterpret_cast<uint64_t>(static_cast<VkCommandBuffer>(
+						m_CommandStreamManager->getStreamCommandBuffer(handle)
+				)),
+				label
+		);
+	}
+	
 }