diff --git a/include/vkcv/Buffer.hpp b/include/vkcv/Buffer.hpp
index 5c21b1ce1d2d84afad6816fd8bf5f66a82b80941..5a95471bf2ccfb0709ee31e1e6131817575ee0ff 100644
--- a/include/vkcv/Buffer.hpp
+++ b/include/vkcv/Buffer.hpp
@@ -4,58 +4,70 @@
  * @file vkcv/Buffer.hpp
  * @brief template buffer class, template for type security, implemented here because template classes can't be written in .cpp
  */
+#include "Handles.hpp"
 #include "BufferManager.hpp"
 
 namespace vkcv {
 
 	template<typename T>
 	class Buffer {
+		friend class Core;
 	public:
 		// explicit destruction of default constructor
 		Buffer<T>() = delete;
-
-		BufferType getType() {
+		
+		[[nodiscard]]
+		const BufferHandle& getHandle() const {
+			return m_handle;
+		}
+		
+		[[nodiscard]]
+		BufferType getType() const {
 			return m_type;
 		};
 		
-		size_t getCount() {
+		[[nodiscard]]
+		size_t getCount() const {
 			return m_count;
 		}
 		
-		size_t getSize() {
+		[[nodiscard]]
+		size_t getSize() const {
 			return m_count * sizeof(T);
 		}
 		
 		void fill(T* data, size_t count = 0, size_t offset = 0) {
-			 m_manager->fillBuffer(m_handle_id, data, count * sizeof(T), offset * sizeof(T));
+			 m_manager->fillBuffer(m_handle, data, count * sizeof(T), offset * sizeof(T));
 		}
 		
+		[[nodiscard]]
 		T* map(size_t offset = 0, size_t count = 0) {
-			return reinterpret_cast<T*>(m_manager->mapBuffer(m_handle_id, offset * sizeof(T), count * sizeof(T)));
+			return reinterpret_cast<T*>(m_manager->mapBuffer(m_handle, offset * sizeof(T), count * sizeof(T)));
 		}
 
 		void unmap() {
-			m_manager->unmapBuffer(m_handle_id);
-		}
-		
-		static Buffer<T> create(BufferManager* manager, BufferType type, size_t count, BufferMemoryType memoryType) {
-			return Buffer<T>(manager, manager->createBuffer(type, count * sizeof(T), memoryType), type, count, memoryType);
+			m_manager->unmapBuffer(m_handle);
 		}
 
 	private:
 		BufferManager* const m_manager;
-		const uint64_t m_handle_id;
+		const BufferHandle m_handle;
 		const BufferType m_type;
 		const size_t m_count;
 		const BufferMemoryType m_memoryType;
 		
-		Buffer<T>(BufferManager* manager, uint64_t id, BufferType type, size_t count, BufferMemoryType memoryType) :
+		Buffer<T>(BufferManager* manager, BufferHandle handle, BufferType type, size_t count, BufferMemoryType memoryType) :
 				m_manager(manager),
-				m_handle_id(id),
+				m_handle(handle),
 				m_type(type),
 				m_count(count),
 				m_memoryType(memoryType)
 		{}
 		
+		[[nodiscard]]
+		static Buffer<T> create(BufferManager* manager, BufferType type, size_t count, BufferMemoryType memoryType) {
+			return Buffer<T>(manager, manager->createBuffer(type, count * sizeof(T), memoryType), type, count, memoryType);
+		}
+		
 	};
 }
diff --git a/include/vkcv/BufferManager.hpp b/include/vkcv/BufferManager.hpp
index abda720f98f649d64b17a15848ae99320e11ae3e..52e338483af7ddd01b6345b4ff1d0187ae4fbd8a 100644
--- a/include/vkcv/BufferManager.hpp
+++ b/include/vkcv/BufferManager.hpp
@@ -3,6 +3,8 @@
 #include <vector>
 #include <vulkan/vulkan.hpp>
 
+#include "Handles.hpp"
+
 namespace vkcv
 {
 	enum class BufferType {
@@ -36,7 +38,7 @@ namespace vkcv
 		
 		Core* m_core;
 		std::vector<Buffer> m_buffers;
-		uint64_t m_stagingBuffer;
+		BufferHandle m_stagingBuffer;
 		
 		BufferManager() noexcept;
 		
@@ -58,67 +60,67 @@ namespace vkcv
 		 * @param type Type of buffer
 		 * @param size Size of buffer in bytes
 		 * @param memoryType Type of buffers memory
-		 * @return New buffer handle id
+		 * @return New buffer handle
 		 */
-		uint64_t createBuffer(BufferType type, size_t size, BufferMemoryType memoryType);
+		BufferHandle createBuffer(BufferType type, size_t size, BufferMemoryType memoryType);
 		
 		/**
 		 * Returns the Vulkan buffer handle of a buffer
 		 * represented by a given buffer handle id.
 		 *
-		 * @param id Buffer handle id
+		 * @param handle Buffer handle
 		 * @return Vulkan buffer handle
 		 */
 		[[nodiscard]]
-		vk::Buffer getBuffer(uint64_t id) const;
+		vk::Buffer getBuffer(const BufferHandle& handle) const;
 		
 		/**
 		 * Returns the Vulkan device memory handle of a buffer
 		 * represented by a given buffer handle id.
 		 *
-		 * @param id Buffer handle id
+		 * @param handle Buffer handle
 		 * @return Vulkan device memory handle
 		 */
 		[[nodiscard]]
-		vk::DeviceMemory getDeviceMemory(uint64_t id) const;
+		vk::DeviceMemory getDeviceMemory(const BufferHandle& handle) const;
 		
 		/**
 		 * Fills a buffer represented by a given buffer
 		 * handle id with custom data.
 		 *
-		 * @param id Buffer handle id
+		 * @param handle Buffer handle
 		 * @param data Pointer to data
 		 * @param size Size of data in bytes
 		 * @param offset Offset to fill in data in bytes
 		 */
-		void fillBuffer(uint64_t id, void* data, size_t size, size_t offset);
+		void fillBuffer(const BufferHandle& handle, void* data, size_t size, size_t offset);
 		
 		/**
 		 * Maps memory to a buffer represented by a given
 		 * buffer handle id and returns it.
 		 *
-		 * @param id Buffer handle id
+		 * @param handle Buffer handle
 		 * @param offset Offset of mapping in bytes
 		 * @param size Size of mapping in bytes
 		 * @return Pointer to mapped memory
 		 */
-		void* mapBuffer(uint64_t id, size_t offset, size_t size);
+		void* mapBuffer(const BufferHandle& handle, size_t offset, size_t size);
 		
 		/**
 		 * Unmaps memory from a buffer represented by a given
 		 * buffer handle id.
 		 *
-		 * @param id Buffer handle id
+		 * @param handle Buffer handle
 		 */
-		void unmapBuffer(uint64_t id);
+		void unmapBuffer(const BufferHandle& handle);
 	
 		/**
 		 * Destroys and deallocates buffer represented by a given
 		 * buffer handle id.
 		 *
-		 * @param id Buffer handle id
+		 * @param handle Buffer handle
 		 */
-		void destroyBuffer(uint64_t id);
+		void destroyBuffer(const BufferHandle& handle);
 		
 	};
 	
diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp
index cb7c7356aef589ee8aef03b904d48021bdb75057..e9b5112888782ae5be373f8a63777b7fc3503713 100644
--- a/src/vkcv/BufferManager.cpp
+++ b/src/vkcv/BufferManager.cpp
@@ -9,7 +9,7 @@
 namespace vkcv {
 	
 	BufferManager::BufferManager() noexcept :
-		m_core(nullptr), m_buffers(), m_stagingBuffer(UINT64_MAX)
+		m_core(nullptr), m_buffers(), m_stagingBuffer(BufferHandle{ UINT64_MAX })
 	{
 	}
 	
@@ -23,7 +23,7 @@ namespace vkcv {
 	
 	BufferManager::~BufferManager() noexcept {
 		for (size_t id = 0; id < m_buffers.size(); id++) {
-			destroyBuffer(id);
+			destroyBuffer(BufferHandle{ id });
 		}
 	}
 	
@@ -52,7 +52,7 @@ namespace vkcv {
 		return memoryTypeIndex;
 	}
 	
-	uint64_t BufferManager::createBuffer(BufferType type, size_t size, BufferMemoryType memoryType) {
+	BufferHandle BufferManager::createBuffer(BufferType type, size_t size, BufferMemoryType memoryType) {
 		vk::BufferCreateFlags createFlags;
 		vk::BufferUsageFlags usageFlags;
 		
@@ -115,7 +115,7 @@ namespace vkcv {
 		
 		const uint64_t id = m_buffers.size();
 		m_buffers.push_back({ buffer, memory, size, nullptr, mappable });
-		return id;
+		return BufferHandle{ id };
 	}
 	
 	struct StagingStepInfo {
@@ -178,7 +178,9 @@ namespace vkcv {
 		);
 	}
 	
-	vk::Buffer BufferManager::getBuffer(uint64_t id) const {
+	vk::Buffer BufferManager::getBuffer(const BufferHandle& handle) const {
+		const uint64_t id = handle.id;
+		
 		if (id >= m_buffers.size()) {
 			return nullptr;
 		}
@@ -188,7 +190,9 @@ namespace vkcv {
 		return buffer.m_handle;
 	}
 	
-	vk::DeviceMemory BufferManager::getDeviceMemory(uint64_t id) const {
+	vk::DeviceMemory BufferManager::getDeviceMemory(const BufferHandle& handle) const {
+		const uint64_t id = handle.id;
+		
 		if (id >= m_buffers.size()) {
 			return nullptr;
 		}
@@ -198,7 +202,9 @@ namespace vkcv {
 		return buffer.m_memory;
 	}
 	
-	void BufferManager::fillBuffer(uint64_t id, void *data, size_t size, size_t offset) {
+	void BufferManager::fillBuffer(const BufferHandle& handle, void *data, size_t size, size_t offset) {
+		const uint64_t id = handle.id;
+		
 		if (size == 0) {
 			size = SIZE_MAX;
 		}
@@ -226,7 +232,7 @@ namespace vkcv {
 			memcpy(mapped, data, max_size);
 			device.unmapMemory(buffer.m_memory);
 		} else {
-			auto& stagingBuffer = m_buffers[m_stagingBuffer];
+			auto& stagingBuffer = m_buffers[ m_stagingBuffer.id ];
 			
 			StagingStepInfo info;
 			info.data = data;
@@ -246,7 +252,9 @@ namespace vkcv {
 		}
 	}
 	
-	void* BufferManager::mapBuffer(uint64_t id, size_t offset, size_t size) {
+	void* BufferManager::mapBuffer(const BufferHandle& handle, size_t offset, size_t size) {
+		const uint64_t id = handle.id;
+		
 		if (size == 0) {
 			size = SIZE_MAX;
 		}
@@ -272,7 +280,9 @@ namespace vkcv {
 		return buffer.m_mapped;
 	}
 	
-	void BufferManager::unmapBuffer(uint64_t id) {
+	void BufferManager::unmapBuffer(const BufferHandle& handle) {
+		const uint64_t id = handle.id;
+		
 		if (id >= m_buffers.size()) {
 			return;
 		}
@@ -289,7 +299,9 @@ namespace vkcv {
 		buffer.m_mapped = nullptr;
 	}
 	
-	void BufferManager::destroyBuffer(uint64_t id) {
+	void BufferManager::destroyBuffer(const BufferHandle& handle) {
+		const uint64_t id = handle.id;
+		
 		if (id >= m_buffers.size()) {
 			return;
 		}