diff --git a/config/Sources.cmake b/config/Sources.cmake
index bdcbc1c6549b425f176b6fc97a4f9b04c0b0d8ee..ea95d152280fde1dcfdd93e7e48d1f8b58d3bb9e 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -1,6 +1,9 @@
 
 # adding all source files and header files of the framework:
 set(vkcv_sources
+		${vkcv_include}/vkcv/Features.hpp
+		${vkcv_source}/vkcv/Features.cpp
+		
 		${vkcv_include}/vkcv/FeatureManager.hpp
 		${vkcv_source}/vkcv/FeatureManager.cpp
 		
diff --git a/include/vkcv/Context.hpp b/include/vkcv/Context.hpp
index 76d60525557456427c86479cf687f771f96f17c0..1160857cb2cdbbb0815390ff1f8405dda0f83796 100644
--- a/include/vkcv/Context.hpp
+++ b/include/vkcv/Context.hpp
@@ -5,7 +5,7 @@
 
 #include "QueueManager.hpp"
 #include "DrawcallRecording.hpp"
-#include "FeatureManager.hpp"
+#include "Features.hpp"
 
 namespace vkcv
 {
@@ -45,8 +45,8 @@ namespace vkcv
         static Context create(const char *applicationName,
 							  uint32_t applicationVersion,
 							  const std::vector<vk::QueueFlagBits>& queueFlags,
-							  const std::vector<const char *>& instanceExtensions,
-							  const std::vector<const char *>& deviceExtensions);
+							  const Features& features,
+							  const std::vector<const char*>& instanceExtensions = {});
 
     private:
         /**
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 7f23c38467b372cc553e1b26af75577bb3f518c8..e7f6688b3d1d1237fbe9d177cd976ec55da85fb8 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -7,14 +7,14 @@
 #include <memory>
 #include <vulkan/vulkan.hpp>
 
-#include "vkcv/Context.hpp"
-#include "vkcv/Swapchain.hpp"
-#include "vkcv/Window.hpp"
-#include "vkcv/PassConfig.hpp"
-#include "vkcv/Handles.hpp"
-#include "vkcv/Buffer.hpp"
-#include "vkcv/Image.hpp"
-#include "vkcv/PipelineConfig.hpp"
+#include "Context.hpp"
+#include "Swapchain.hpp"
+#include "Window.hpp"
+#include "PassConfig.hpp"
+#include "Handles.hpp"
+#include "Buffer.hpp"
+#include "Image.hpp"
+#include "PipelineConfig.hpp"
 #include "CommandResources.hpp"
 #include "SyncResources.hpp"
 #include "Result.hpp"
@@ -139,8 +139,8 @@ namespace vkcv
                            const char *applicationName,
                            uint32_t applicationVersion,
                            const std::vector<vk::QueueFlagBits>& queueFlags    = {},
-                           const std::vector<const char*>& instanceExtensions  = {},
-                           const std::vector<const char*>& deviceExtensions    = {});
+						   const Features& features = {},
+						   const std::vector<const char *>& instanceExtensions = {});
 
         /**
          * Creates a basic vulkan graphics pipeline using @p config from the pipeline config class and returns it using the @p handle.
diff --git a/include/vkcv/FeatureManager.hpp b/include/vkcv/FeatureManager.hpp
index 9e472a38bfca33ce507515148a919a8b867554cb..cf945d7498fec83f0b128294caa3ba267b69a6b3 100644
--- a/include/vkcv/FeatureManager.hpp
+++ b/include/vkcv/FeatureManager.hpp
@@ -93,12 +93,12 @@ namespace vkcv {
 		FeatureManager& operator=(FeatureManager&& other) noexcept;
 		
 		[[nodiscard]]
-		bool isExtensionSupported(const char *extension) const;
+		bool isExtensionSupported(const std::string& extension) const;
 		
-		bool useExtension(const char *extension, bool required = true);
+		bool useExtension(const std::string& extension, bool required = true);
 		
 		[[nodiscard]]
-		bool isExtensionActive(const char *extension) const;
+		bool isExtensionActive(const std::string& extension) const;
 		
 		[[nodiscard]]
 		const std::vector<const char*>& getActiveExtensions() const;
diff --git a/include/vkcv/Features.hpp b/include/vkcv/Features.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f1329106abbca99dbb9b81661afeef3221de155e
--- /dev/null
+++ b/include/vkcv/Features.hpp
@@ -0,0 +1,80 @@
+#pragma once
+
+#include <functional>
+#include <vector>
+
+#include "FeatureManager.hpp"
+
+namespace vkcv {
+	
+	typedef std::function<bool(FeatureManager&)> Feature;
+	
+	class Features {
+	private:
+		std::vector<Feature> m_features;
+		
+	public:
+		Features() = default;
+		Features(const Features& other) = default;
+		Features(Features&& other) = default;
+		~Features() = default;
+		
+		Features& operator=(const Features& other) = default;
+		Features& operator=(Features&& other) = default;
+		
+		void requireExtension(const std::string& extension);
+		
+		void requireExtensionFeature(const std::string& extension,
+									 const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction);
+		
+		template<typename T>
+		void requireExtensionFeature(const std::string& extension, const std::function<void(T&)>& featureFunction) {
+			m_features.emplace_back([extension, &featureFunction](FeatureManager& featureManager) {
+				if (featureManager.useExtension(extension, true)) {
+					return featureManager.template useFeatures<T>(featureFunction, true);
+				} else {
+					return false;
+				}
+			});
+		}
+		
+		void requireFeature(const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction);
+		
+		template<typename T>
+		void requireFeature(const std::function<void(T&)>& featureFunction) {
+			m_features.emplace_back([&featureFunction](FeatureManager& featureManager) {
+				return featureManager.template useFeatures<T>(featureFunction, true);
+			});
+		}
+		
+		void tryExtension(const std::string& extension);
+		
+		void tryExtensionFeature(const std::string& extension,
+								 const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction);
+		
+		template<typename T>
+		void tryExtensionFeature(const std::string& extension, const std::function<void(T&)>& featureFunction) {
+			m_features.emplace_back([extension, &featureFunction](FeatureManager& featureManager) {
+				if (featureManager.useExtension(extension, false)) {
+					return featureManager.template useFeatures<T>(featureFunction, false);
+				} else {
+					return false;
+				}
+			});
+		}
+		
+		void tryFeature(const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction);
+		
+		template<typename T>
+		void tryFeature(const std::function<void(T&)>& featureFunction) {
+			m_features.emplace_back([&featureFunction](FeatureManager& featureManager) {
+				return featureManager.template useFeatures<T>(featureFunction, false);
+			});
+		}
+		
+		[[nodiscard]]
+		const std::vector<Feature>& getList() const;
+		
+	};
+	
+}
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index 731d3e56975ff0cd2d8e6d503a19d56de1b922fe..f784c13007e59ea2461252b02a24e3d790a58107 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -18,14 +18,16 @@ int main(int argc, const char** argv) {
 		windowHeight,
 		true
 	);
+	
+	vkcv::Features features;
+	features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
 
 	vkcv::Core core = vkcv::Core::create(
 		window,
 		applicationName,
 		VK_MAKE_VERSION(0, 0, 1),
 		{ vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer },
-		{},
-		{ "VK_KHR_swapchain" }
+		features
 	);
 
 	vkcv::asset::Scene mesh;
diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp
index 527eba8c3a1e020e14d92f5d305e2ddced936333..6ac367e41906a276e6c739e0242b859eae5b8f15 100644
--- a/projects/first_scene/src/main.cpp
+++ b/projects/first_scene/src/main.cpp
@@ -29,13 +29,15 @@ int main(int argc, const char** argv) {
 	
 	cameraManager.getCamera(camIndex1).setNearFar(0.1f, 30.0f);
 
+	vkcv::Features features;
+	features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+	
 	vkcv::Core core = vkcv::Core::create(
 		window,
 		applicationName,
 		VK_MAKE_VERSION(0, 0, 1),
 		{ vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer },
-		{},
-		{ "VK_KHR_swapchain" }
+		features
 	);
 	
 	vkcv::scene::Scene scene = vkcv::scene::Scene::load(core, std::filesystem::path(
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index 253efad491e6e320ba5e5e8b270b187e2e79da82..de5d345fec7635ea20e7f025f5faed90c35f6cd8 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -16,14 +16,16 @@ int main(int argc, const char** argv) {
 		windowHeight,
 		false
 	);
+	
+	vkcv::Features features;
+	features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
 
 	vkcv::Core core = vkcv::Core::create(
 		window,
 		applicationName,
 		VK_MAKE_VERSION(0, 0, 1),
 		{ vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute },
-		{},
-		{ "VK_KHR_swapchain" }
+		features
 	);
 
 	const auto& context = core.getContext();
diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp
index 3a94de5842f3e70625729c9755b8c88048ece2ec..18d705ecb6b4e1817d32695eeeaf55406c95dab4 100644
--- a/projects/mesh_shader/src/main.cpp
+++ b/projects/mesh_shader/src/main.cpp
@@ -86,14 +86,21 @@ int main(int argc, const char** argv) {
 		windowHeight,
 		false
 	);
+	
+	vkcv::Features features;
+	features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+	features.requireExtensionFeature<vk::PhysicalDeviceMeshShaderFeaturesNV>(
+			VK_NV_MESH_SHADER_EXTENSION_NAME, [](vk::PhysicalDeviceMeshShaderFeaturesNV& features) {
+		features.setTaskShader(true);
+		features.setMeshShader(true);
+	});
 
 	vkcv::Core core = vkcv::Core::create(
 		window,
 		applicationName,
 		VK_MAKE_VERSION(0, 0, 1),
 		{ vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute },
-		{},
-		{ "VK_KHR_swapchain", VK_NV_MESH_SHADER_EXTENSION_NAME }
+		features
 	);
 
     vkcv::gui::GUI gui (core, window);
diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp
index 07ba6b194ce72dbad15a921ca13a4814c6d4f5df..1aafa57fa343b1c3bcb6571e82bd4b359fd8180e 100644
--- a/projects/particle_simulation/src/main.cpp
+++ b/projects/particle_simulation/src/main.cpp
@@ -24,13 +24,15 @@ int main(int argc, const char **argv) {
 
     vkcv::camera::CameraManager cameraManager(window);
 
+	vkcv::Features features;
+	features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+	
     vkcv::Core core = vkcv::Core::create(
             window,
             applicationName,
             VK_MAKE_VERSION(0, 0, 1),
             {vk::QueueFlagBits::eTransfer, vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute},
-            {},
-            {"VK_KHR_swapchain"}
+			features
     );
 
     auto particleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3,
diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp
index e7f9caa493714d30f13f64c292f1b6e51e5170b1..3c23c7eabbbdc5d83d37bde79b43a2730b1f28b2 100644
--- a/projects/voxelization/src/main.cpp
+++ b/projects/voxelization/src/main.cpp
@@ -80,14 +80,18 @@ int main(int argc, const char** argv) {
 	cameraManager.getCamera(camIndex).setFov(glm::radians(37.8));	// fov of a 35mm lens
 	
 	cameraManager.getCamera(camIndex2).setNearFar(0.1f, 30.0f);
-
+	
+	vkcv::Features features;
+	features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+	features.requireExtension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
+	features.requireExtension(VK_KHR_16BIT_STORAGE_EXTENSION_NAME);
+	
 	vkcv::Core core = vkcv::Core::create(
 		window,
 		applicationName,
 		VK_MAKE_VERSION(0, 0, 1),
 		{ vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute },
-		{},
-		{ "VK_KHR_swapchain", "VK_KHR_shader_float16_int8", "VK_KHR_16bit_storage" }
+		features
 	);
 
 	vkcv::asset::Scene mesh;
diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp
index 75d409d7ad396206a7b7ad0db0fe775fa82986f3..f48fad1a9022cbf99f6452c319d629060befbd98 100644
--- a/src/vkcv/Context.cpp
+++ b/src/vkcv/Context.cpp
@@ -190,8 +190,8 @@ namespace vkcv
 	Context Context::create(const char *applicationName,
 							uint32_t applicationVersion,
 							const std::vector<vk::QueueFlagBits>& queueFlags,
-							const std::vector<const char *>& instanceExtensions,
-							const std::vector<const char *>& deviceExtensions) {
+							const Features& features,
+							const std::vector<const char*>& instanceExtensions) {
 		// check for layer support
 		
 		const std::vector<vk::LayerProperties>& layerProperties = vk::enumerateInstanceLayerProperties();
@@ -282,8 +282,8 @@ namespace vkcv
 			features.setShaderInt16(true);
 		});
 		
-		for (const auto& extension : deviceExtensions) {
-			featureManager.useExtension(extension);
+		for (const auto& feature : features.getList()) {
+			feature(featureManager);
 		}
 		
 		const auto& extensions = featureManager.getActiveExtensions();
@@ -313,16 +313,6 @@ namespace vkcv
 		deviceCreateInfo.ppEnabledLayerNames = validationLayers.data();
 #endif
 		
-		for (const auto& extension : deviceExtensions) {
-			if (0 == strcmp(extension, VK_NV_MESH_SHADER_EXTENSION_NAME)) {
-				featureManager.useFeatures<vk::PhysicalDeviceMeshShaderFeaturesNV>(
-						[](vk::PhysicalDeviceMeshShaderFeaturesNV& features) {
-					features.setTaskShader(true);
-					features.setMeshShader(true);
-				});
-			}
-		}
-		
 		deviceCreateInfo.setPNext(&(featureManager.getFeatures()));
 		
 		vk::Device device = physicalDevice.createDevice(deviceCreateInfo);
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 69da1106df8c8a946e1fcdc9ce1afd7c2825362a..1ae1c3164054107b6bd9f7dec822f45180a07577 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -54,14 +54,14 @@ namespace vkcv
                       const char *applicationName,
                       uint32_t applicationVersion,
                       const std::vector<vk::QueueFlagBits>& queueFlags,
-                      const std::vector<const char *>& instanceExtensions,
-                      const std::vector<const char *>& deviceExtensions)
+					  const Features& features,
+                      const std::vector<const char *>& instanceExtensions)
     {
         Context context = Context::create(
         		applicationName, applicationVersion,
         		queueFlags,
-        		instanceExtensions,
-        		deviceExtensions
+				features,
+        		instanceExtensions
 		);
 
         Swapchain swapChain = Swapchain::create(window, context);
diff --git a/src/vkcv/FeatureManager.cpp b/src/vkcv/FeatureManager.cpp
index 416858c836f089f87f3d7efeb5b5d48dbb8cf7fb..18307999bb28ed60791a801b952619eeeba51a53 100644
--- a/src/vkcv/FeatureManager.cpp
+++ b/src/vkcv/FeatureManager.cpp
@@ -372,9 +372,9 @@ m_physicalDevice.getFeatures2(&query)
 		return *this;
 	}
 	
-	bool FeatureManager::isExtensionSupported(const char *extension) const {
+	bool FeatureManager::isExtensionSupported(const std::string& extension) const {
 		for (const auto& supported : m_supportedExtensions) {
-			if (0 == strcmp(supported, extension)) {
+			if (0 == strcmp(supported, extension.c_str())) {
 				return true;
 			}
 		}
@@ -382,16 +382,17 @@ m_physicalDevice.getFeatures2(&query)
 		return false;
 	}
 	
-	bool FeatureManager::useExtension(const char *extension, bool required) {
-		const char* clone = strclone(extension);
+	bool FeatureManager::useExtension(const std::string& extension, bool required) {
+		const char* clone = strclone(extension.c_str());
 		
 		if (!clone) {
-			vkcv_log(LogLevel::WARNING, "Extension '%s' is not valid", extension);
+			vkcv_log(LogLevel::WARNING, "Extension '%s' is not valid", extension.c_str());
 			return false;
 		}
 		
 		if (!isExtensionSupported(extension)) {
-			vkcv_log((required? LogLevel::ERROR : LogLevel::WARNING), "Extension '%s' is not supported", extension);
+			vkcv_log((required? LogLevel::ERROR : LogLevel::WARNING), "Extension '%s' is not supported",
+					 extension.c_str());
 			
 			delete[] clone;
 			return false;
@@ -401,9 +402,9 @@ m_physicalDevice.getFeatures2(&query)
 		return true;
 	}
 	
-	bool FeatureManager::isExtensionActive(const char *extension) const {
+	bool FeatureManager::isExtensionActive(const std::string& extension) const {
 		for (const auto& supported : m_activeExtensions) {
-			if (0 == strcmp(supported, extension)) {
+			if (0 == strcmp(supported, extension.c_str())) {
 				return true;
 			}
 		}
diff --git a/src/vkcv/Features.cpp b/src/vkcv/Features.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cdfbcabbcd72ead650a739d101109e2d33fc2e75
--- /dev/null
+++ b/src/vkcv/Features.cpp
@@ -0,0 +1,56 @@
+
+#include "vkcv/Features.hpp"
+
+namespace vkcv {
+	
+	void Features::requireExtension(const std::string& extension) {
+		m_features.emplace_back([extension](FeatureManager& featureManager) {
+			return featureManager.useExtension(extension, true);
+		});
+	}
+	
+	void Features::requireExtensionFeature(const std::string &extension,
+										   const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction) {
+		m_features.emplace_back([extension, &featureFunction](FeatureManager& featureManager) {
+			if (featureManager.useExtension(extension, true)) {
+				return featureManager.useFeatures(featureFunction, true);
+			} else {
+				return false;
+			}
+		});
+	}
+	
+	void Features::requireFeature(const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction) {
+		m_features.emplace_back([&featureFunction](FeatureManager& featureManager) {
+			return featureManager.useFeatures(featureFunction, true);
+		});
+	}
+	
+	void Features::tryExtension(const std::string& extension) {
+		m_features.emplace_back([extension](FeatureManager& featureManager) {
+			return featureManager.useExtension(extension, false);
+		});
+	}
+	
+	void Features::tryExtensionFeature(const std::string &extension,
+									   const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction) {
+		m_features.emplace_back([extension, &featureFunction](FeatureManager& featureManager) {
+			if (featureManager.useExtension(extension, false)) {
+				return featureManager.useFeatures(featureFunction, false);
+			} else {
+				return false;
+			}
+		});
+	}
+	
+	void Features::tryFeature(const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction) {
+		m_features.emplace_back([&featureFunction](FeatureManager& featureManager) {
+			return featureManager.useFeatures(featureFunction, false);
+		});
+	}
+	
+	const std::vector<Feature>& Features::getList() const {
+		return m_features;
+	}
+
+}