diff --git a/include/vkcv/PipelineConfig.hpp b/include/vkcv/PipelineConfig.hpp
index 5aa4dac939d57988af815161a4cb474247d2a9cc..1ad6be8d1979c8a89f7de9dbe24ff13b5f5bb3fa 100644
--- a/include/vkcv/PipelineConfig.hpp
+++ b/include/vkcv/PipelineConfig.hpp
@@ -33,10 +33,10 @@ namespace vkcv {
          */
         PipelineConfig(const ShaderProgram& shaderProgram, uint32_t width, uint32_t height, PassHandle &passHandle);
 
-		ShaderProgram m_shaderProgram;
-        uint32_t m_height;
-        uint32_t m_width;
-        PassHandle m_passHandle;
+		ShaderProgram m_ShaderProgram;
+        uint32_t m_Height;
+        uint32_t m_Width;
+        PassHandle m_PassHandle;
     };
 
 }
diff --git a/include/vkcv/ShaderProgram.hpp b/include/vkcv/ShaderProgram.hpp
index ea0cb0f17c1ac5a292c51365fe3d0007c2e7ebfc..172e906fca457c6245855639275054514958b69d 100644
--- a/include/vkcv/ShaderProgram.hpp
+++ b/include/vkcv/ShaderProgram.hpp
@@ -5,35 +5,35 @@
  * @brief ShaderProgram class to handle and prepare the shader stages for a graphics pipeline
  */
 
-#define GLFW_INCLUDE_VULKAN
-#include <vector>
+#include <unordered_map>
 #include <fstream>
 #include <iostream>
+#include <filesystem>
 #include <vulkan/vulkan.hpp>
 
 namespace vkcv {
 
-	class ShaderProgram final {
+    enum class ShaderStage
+    {
+        VERTEX,
+        TESS_CONTROL,
+        TESS_EVAL,
+        GEOMETRY,
+        FRAGMENT,
+        COMPUTE
+    };
+
+    struct Shader
+    {
+        std::vector<char> shaderCode;
+        ShaderStage shaderStage;
+    };
+
+	class ShaderProgram
+	{
     public:
-
-        enum class ShaderStage {
-            VERTEX,
-            FRAGMENT,
-            COMPUTE
-        };
-
-
-        /**
-        * destructor of ShaderProgram, does nothing so far
-        */
-        ~ShaderProgram();
-
-        /**
-        * Creates a shader program.
-        * So far it only calls the constructor.
-        * @param[in] context of the app
-        */
-        static ShaderProgram create();
+        ShaderProgram() noexcept; // ctor
+        ~ShaderProgram() = default; // dtor
 
         /**
         * Adds a shader into the shader program.
@@ -42,92 +42,19 @@ namespace vkcv {
         * @param[in] flag that signals the respective shaderStage (e.g. VK_SHADER_STAGE_VERTEX_BIT)
         * @param[in] relative path to the shader code (e.g. "../../../../../shaders/vert.spv")
         */
-        void addShader(ShaderProgram::ShaderStage shaderStage, const std::string& filepath);
-
-        /**
-        * Tests if the shader program contains a certain shader stage.
-        * @param[in] flag that signals the respective shader stage (e.g. VK_SHADER_STAGE_VERTEX_BIT)
-        * @return boolean that is true if the shader program contains the shader stage
-        */
-        bool containsShaderStage(ShaderProgram::ShaderStage shaderStage) const;
-
-        /**
-        * Deletes the given shader stage in the shader program.
-        * @param[in] flag that signals the respective shader stage (e.g. VK_SHADER_STAGE_VERTEX_BIT)
-        * @return boolean that is false if the shader stage was not found in the shader program
-        */
-        bool deleteShaderStage(ShaderProgram::ShaderStage shaderStage);
-
-        /**
-        * Returns a list with all the shader stages in the shader program.
-        * Needed for the transfer to the pipeline.
-        * @return vector list with all shader stage info structs
-        */
-        std::vector<vk::ShaderStageFlagBits> getShaderStages() const;
-
-        /**
-        * Returns a list with all the shader code in the shader program.
-        * Needed for the transfer to the pipeline.
-        * @return vector list with all shader code char vecs
-        */
-        std::vector<std::vector<char>> getShaderCode() const;
+        bool addShader(ShaderStage shaderStage, const std::filesystem::path &shaderPath);
 
         /**
-        * Returns the number of shader stages in the shader program.
+        * Returns the shader program's shader of the specified shader.
         * Needed for the transfer to the pipeline.
-        * @return integer with the number of stages
+        * @return Shader object consisting of buffer with shader code and shader stage enum
         */
-        int getShaderStagesCount() const;
-
+        const Shader &getShader(ShaderStage shaderStage) const;
 
+        bool existsShader(ShaderStage shaderStage) const;
 
 	private:
-
-	    struct ShaderStages {
-            std::vector<std::vector<char>> shaderCode;
-            std::vector<vk::ShaderStageFlagBits> shaderStageFlag;
-	    };
-
-		ShaderStages m_shaderStages;
-
-		/**
-		* Constructor of ShaderProgram requires a context for the logical device. 
-		* @param context of the app
-		*/
-		ShaderProgram();
-		
-		/**
-		* Reads the file of a given shader code. 
-		* Only used within the class. 
-		* @param[in] relative path to the shader code 
-		* @return vector of chars as a buffer for the code 
-		*/
-		std::vector<char> readFile(const std::string& filepath);
-
-        /**
-		* Converts ShaderStage Enum into vk::ShaderStageFlagBits
-		* @param[in] ShaderStage enum
-		* @return vk::ShaderStageFlagBits
-		*/
-        vk::ShaderStageFlagBits convertToShaderStageFlagBits(ShaderProgram::ShaderStage shaderStage) const;
-
-		/**
-		* Creates a shader module that encapsulates the read shader code. 
-		* Only used within the class. 
-		* Shader modules are destroyed after respective shader stages are created. 
-		* @param[in] a vector of chars as a buffer for the code 
-		* @return shader module 
-		*/
-		//vk::ShaderModule createShaderModule(const std::vector<char>& shaderCode); -> Core
-
-		/**
-		* Creates a shader stage (info struct) for the to be added shader. 
-		* Only used within the class. 
-		* @param[in] Shader module that encapsulates the shader code 
-		* @param[in] flag that signals the respective shaderStage 
-		* @return pipeline shader stage info struct 
-		*/ 
-		//vk::PipelineShaderStageCreateInfo createShaderStage(vk::ShaderModule& shaderModule, vk::ShaderStageFlagBits shaderStage); -> Core
+        std::unordered_map<ShaderStage, Shader> m_Shaders;
 
 	};
 }
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index 4c2a380ea1509efaaaa14b3b0b8a607cb12e4d19..e725c83ae44c71cc9184f5c2b0f0779e7b562732 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -57,9 +57,9 @@ int main(int argc, const char** argv) {
 		return EXIT_FAILURE;
 	}
 
-	vkcv::ShaderProgram triangleShaderProgram = vkcv::ShaderProgram::create();
-	triangleShaderProgram.addShader(vkcv::ShaderProgram::ShaderStage::VERTEX, "shaders/vert.spv");
-	triangleShaderProgram.addShader(vkcv::ShaderProgram::ShaderStage::FRAGMENT, "shaders/frag.spv");
+	vkcv::ShaderProgram triangleShaderProgram{};
+	triangleShaderProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("shaders/vert.spv"));
+	triangleShaderProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("shaders/frag.spv"));
 
 	const vkcv::PipelineConfig trianglePipelineDefinition(triangleShaderProgram, windowWidth, windowHeight, trianglePass);
 	vkcv::PipelineHandle trianglePipeline = core.createGraphicsPipeline(trianglePipelineDefinition);
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 07e0081678af075b5ccd57188d003304730ca754..867426b00da77c35f983ab03fb25141fa08005e3 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -497,7 +497,7 @@ namespace vkcv
 
     PipelineHandle Core::createGraphicsPipeline(const PipelineConfig &config)
     {
-        const vk::RenderPass &pass = m_PassManager->getVkPass(config.m_passHandle);
+        const vk::RenderPass &pass = m_PassManager->getVkPass(config.m_PassHandle);
         return m_PipelineManager->createPipeline(config, pass);
     }
 
diff --git a/src/vkcv/PipelineConfig.cpp b/src/vkcv/PipelineConfig.cpp
index 9fed7323fedd9d938a639c22fdf3f20b2a712182..c2b1415f10188f082d8eca576c2143e82f99e7fa 100644
--- a/src/vkcv/PipelineConfig.cpp
+++ b/src/vkcv/PipelineConfig.cpp
@@ -9,5 +9,9 @@
 namespace vkcv {
 
     PipelineConfig::PipelineConfig(const ShaderProgram& shaderProgram, uint32_t width, uint32_t height, PassHandle &passHandle):
-		m_shaderProgram(shaderProgram), m_height(height), m_width(width), m_passHandle(passHandle) {}
+		m_ShaderProgram(shaderProgram),
+		m_Height(height),
+		m_Width(width),
+		m_PassHandle(passHandle)
+		{}
 }
diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp
index 327c443c17077175497a7c942fa83fefd74ba370..416356f4fe9831fbe52b163a2b895dd2247d0b0f 100644
--- a/src/vkcv/PipelineManager.cpp
+++ b/src/vkcv/PipelineManager.cpp
@@ -25,32 +25,16 @@ namespace vkcv
 
     PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, const vk::RenderPass &pass)
     {
-
-        // TODO: this search could be avoided if ShaderProgram could be queried for a specific stage
-        const auto shaderStageFlags = config.m_shaderProgram.getShaderStages();
-        const auto shaderCode = config.m_shaderProgram.getShaderCode();
-        std::vector<char> vertexCode;
-        std::vector<char> fragCode;
-        assert(shaderStageFlags.size() == shaderCode.size());
-        for (int i = 0; i < shaderStageFlags.size(); i++) {
-            switch (shaderStageFlags[i]) {
-                case vk::ShaderStageFlagBits::eVertex: vertexCode = shaderCode[i]; break;
-                case vk::ShaderStageFlagBits::eFragment: fragCode = shaderCode[i]; break;
-                default: std::cout << "Core::createGraphicsPipeline encountered unknown shader stage" << std::endl;
-                return PipelineHandle{0};
-            }
-        }
-
-        const bool foundVertexCode = !vertexCode.empty();
-        const bool foundFragCode = !fragCode.empty();
-        const bool foundRequiredShaderCode = foundVertexCode && foundFragCode;
-        if (!foundRequiredShaderCode) {
+        const bool existsVertexShader = config.m_ShaderProgram.existsShader(ShaderStage::VERTEX);
+        const bool existsFragmentShader = config.m_ShaderProgram.existsShader(ShaderStage::FRAGMENT);
+        if (!(existsVertexShader && existsFragmentShader))
+        {
             std::cout << "Core::createGraphicsPipeline requires vertex and fragment shader code" << std::endl;
             return PipelineHandle{0};
         }
 
         // vertex shader stage
-        // TODO: store shader code as uint32_t in ShaderProgram to avoid pointer cast
+        std::vector<char> vertexCode = config.m_ShaderProgram.getShader(ShaderStage::VERTEX).shaderCode;
         vk::ShaderModuleCreateInfo vertexModuleInfo({}, vertexCode.size(), reinterpret_cast<uint32_t*>(vertexCode.data()));
         vk::ShaderModule vertexModule{};
         if (m_Device.createShaderModule(&vertexModuleInfo, nullptr, &vertexModule) != vk::Result::eSuccess)
@@ -65,6 +49,7 @@ namespace vkcv
         );
 
         // fragment shader stage
+        std::vector<char> fragCode = config.m_ShaderProgram.getShader(ShaderStage::FRAGMENT).shaderCode;
         vk::ShaderModuleCreateInfo fragmentModuleInfo({}, fragCode.size(), reinterpret_cast<uint32_t*>(fragCode.data()));
         vk::ShaderModule fragmentModule{};
         if (m_Device.createShaderModule(&fragmentModuleInfo, nullptr, &fragmentModule) != vk::Result::eSuccess)
@@ -101,8 +86,8 @@ namespace vkcv
         );
 
         // viewport state
-        vk::Viewport viewport(0.f, 0.f, static_cast<float>(config.m_width), static_cast<float>(config.m_height), 0.f, 1.f);
-        vk::Rect2D scissor({ 0,0 }, { config.m_width, config.m_height });
+        vk::Viewport viewport(0.f, 0.f, static_cast<float>(config.m_Width), static_cast<float>(config.m_Height), 0.f, 1.f);
+        vk::Rect2D scissor({ 0,0 }, { config.m_Width, config.m_Height });
         vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo({}, 1, &viewport, 1, &scissor);
 
         // rasterization state
@@ -211,11 +196,11 @@ namespace vkcv
 
     vk::Pipeline PipelineManager::getVkPipeline(const PipelineHandle &handle) const
     {
-        return m_Pipelines[handle.id -1];
+        return m_Pipelines.at(handle.id -1);
     }
 
     vk::PipelineLayout PipelineManager::getVkPipelineLayout(const PipelineHandle &handle) const
     {
-        return m_PipelineLayouts[handle.id - 1];
+        return m_PipelineLayouts.at(handle.id - 1);
     }
 }
\ No newline at end of file
diff --git a/src/vkcv/ShaderProgram.cpp b/src/vkcv/ShaderProgram.cpp
index b995dde0916a13689a025f234aae1d27a1249204..87ccdefbfec0b4891d3152d30aa6c9f6c8c0d5ea 100644
--- a/src/vkcv/ShaderProgram.cpp
+++ b/src/vkcv/ShaderProgram.cpp
@@ -6,114 +6,57 @@
 
 #include "vkcv/ShaderProgram.hpp"
 
-std::vector<const char*> validationLayers = {
-	"VK_LAYER_KHRONOS_validation"
-};
-
-
 namespace vkcv {
-
-	ShaderProgram::ShaderProgram(){
-	    ShaderStages m_shaderStages{};
-	    m_shaderStages.shaderCode = std::vector<std::vector<char>> ();
-	    m_shaderStages.shaderStageFlag = std::vector<vk::ShaderStageFlagBits> ();
-	}
-
-	std::vector<char> ShaderProgram::readFile(const std::string& filepath) {
-		std::ifstream file(filepath, std::ios::ate | std::ios::binary);
+    /**
+     * Reads the file of a given shader code.
+     * Only used within the class.
+     * @param[in] relative path to the shader code
+     * @return vector of chars as a buffer for the code
+     */
+	std::vector<char> readShaderCode(const std::filesystem::path &shaderPath)
+	{
+		std::ifstream file(shaderPath.string(), std::ios::ate | std::ios::binary);
 		if (!file.is_open()) {
-			throw std::runtime_error("The file could not be opened.");
+		    std::cout << "The file could not be opened." << std::endl;
+			return std::vector<char>{};
 		}
 		size_t fileSize = (size_t)file.tellg();
 		std::vector<char> buffer(fileSize);
 		file.seekg(0);
 		file.read(buffer.data(), fileSize);
-		return buffer;
-	}
-
-    vk::ShaderStageFlagBits ShaderProgram::convertToShaderStageFlagBits(ShaderProgram::ShaderStage shaderStage) const{
-        switch (shaderStage) {
-            case ShaderStage::VERTEX:
-                return vk::ShaderStageFlagBits::eVertex;
-            case ShaderStage::FRAGMENT:
-                return vk::ShaderStageFlagBits::eFragment;
-            case ShaderStage::COMPUTE:
-                return vk::ShaderStageFlagBits::eCompute;
+        return buffer;
+	}
+
+	ShaderProgram::ShaderProgram() noexcept :
+	m_Shaders{}
+	{}
+
+	bool ShaderProgram::addShader(ShaderStage shaderStage, const std::filesystem::path &shaderPath)
+	{
+	    if(m_Shaders.find(shaderStage) != m_Shaders.end())
+	        std::cout << "Found existing shader stage. Overwriting."  << std::endl;
+
+	    const std::vector<char> shaderCode = readShaderCode(shaderPath);
+	    if (shaderCode.empty())
+	        return false;
+	    else
+        {
+            Shader shader{shaderCode, shaderStage};
+            m_Shaders.insert(std::make_pair(shaderStage, shader));
+            return true;
         }
-        throw std::runtime_error("Shader Type not yet implemented.");
-	}
-
-	/*vk::ShaderModule ShaderProgram::createShaderModule(const std::vector<char>& shaderCode) {
-		vk::ShaderModuleCreateInfo createInfo({}, shaderCode.size(), reinterpret_cast<const uint32_t*>(shaderCode.data()));
-		vk::ShaderModule shaderModule;
-		if ((m_context.getDevice().createShaderModule(&createInfo, nullptr, &shaderModule)) != vk::Result::eSuccess) {
-			throw std::runtime_error("Failed to create shader module!");
-		}
-		return shaderModule;
-	}*/
-
-	/*vk::PipelineShaderStageCreateInfo ShaderProgram::createShaderStage(vk::ShaderModule& shaderModule, vk::ShaderStageFlagBits shaderStage) {
-		vk::PipelineShaderStageCreateInfo shaderStageInfo({}, shaderStage, shaderModule, "main", {});
-		shaderStageInfo.stage = shaderStage;
-		shaderStageInfo.module = shaderModule;
-		shaderStageInfo.pName = "main";
-		return shaderStageInfo;
-	}*/
-	
-	ShaderProgram::~ShaderProgram() {
-	}
-
-	ShaderProgram ShaderProgram::create() {
-		return ShaderProgram();
 	}
 
-	void ShaderProgram::addShader(ShaderProgram::ShaderStage shaderStage, const std::string& filepath) {
-		if (containsShaderStage(shaderStage)) {
-			throw std::runtime_error("Shader program already contains this particular shader stage.");
-		}
-		else {
-			auto shaderCode = readFile(filepath);
-            vk::ShaderStageFlagBits convertedShaderStage = convertToShaderStageFlagBits(shaderStage);
-			//vk::ShaderModule shaderModule = createShaderModule(shaderCode);
-			//vk::PipelineShaderStageCreateInfo shaderInfo = createShaderStage(shaderModule, shaderStage);
-			//m_shaderStagesList.push_back(shaderInfo);
-			//m_context.getDevice().destroyShaderModule(shaderModule, nullptr);
-			m_shaderStages.shaderCode.push_back(shaderCode);
-			m_shaderStages.shaderStageFlag.push_back(convertedShaderStage);
-		}
+    const Shader &ShaderProgram::getShader(ShaderStage shaderStage) const
+    {
+	    return m_Shaders.at(shaderStage);
 	}
 
-	bool ShaderProgram::containsShaderStage(ShaderProgram::ShaderStage shaderStage) const{
-        vk::ShaderStageFlagBits convertedShaderStage = convertToShaderStageFlagBits(shaderStage);
-		for (int i = 0; i < m_shaderStages.shaderStageFlag.size(); i++) {
-			if (m_shaderStages.shaderStageFlag[i] == convertedShaderStage) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	bool ShaderProgram::deleteShaderStage(ShaderProgram::ShaderStage shaderStage) {
-        vk::ShaderStageFlagBits convertedShaderStage = convertToShaderStageFlagBits(shaderStage);
-		for (int i = 0; i < m_shaderStages.shaderStageFlag.size() - 1; i++) {
-			if (m_shaderStages.shaderStageFlag[i] == convertedShaderStage) {
-			    m_shaderStages.shaderStageFlag.erase(m_shaderStages.shaderStageFlag.begin() + i);
-                m_shaderStages.shaderCode.erase(m_shaderStages.shaderCode.begin() + i);
-				return true;
-			}
-		}
-		return false;
-	}
-
-	std::vector<vk::ShaderStageFlagBits> ShaderProgram::getShaderStages() const{
-		return m_shaderStages.shaderStageFlag;
-	}
-
-    std::vector<std::vector<char>> ShaderProgram::getShaderCode() const {
-	    return m_shaderStages.shaderCode;
-	}
-
-	int ShaderProgram::getShaderStagesCount() const {
-		return m_shaderStages.shaderStageFlag.size();
-	}
+    bool ShaderProgram::existsShader(ShaderStage shaderStage) const
+    {
+	    if(m_Shaders.find(shaderStage) == m_Shaders.end())
+	        return false;
+	    else
+	        return true;
+    }
 }