diff --git a/src/dxvk/dxvk_shader.cpp b/src/dxvk/dxvk_shader.cpp
new file mode 100644
index 000000000..ba464a14f
--- /dev/null
+++ b/src/dxvk/dxvk_shader.cpp
@@ -0,0 +1,30 @@
+#include "dxvk_shader.h"
+
+namespace dxvk {
+  
+  DxvkShader::DxvkShader(
+    const Rc<vk::DeviceFn>&     vkd,
+    const SpirvCodeBuffer&      code)
+  : m_vkd(vkd) {
+    TRACE(this);
+    
+    VkShaderModuleCreateInfo info;
+    info.sType    = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+    info.pNext    = nullptr;
+    info.flags    = 0;
+    info.codeSize = code.size();
+    info.pCode    = code.code();
+    
+    if (m_vkd->vkCreateShaderModule(m_vkd->device(),
+          &info, nullptr, &m_shader) != VK_SUCCESS)
+      throw DxvkError("DxvkShader::DxvkShader: Failed to create shader");
+  }
+  
+  
+  DxvkShader::~DxvkShader() {
+    TRACE(this);
+    m_vkd->vkDestroyShaderModule(
+      m_vkd->device(), m_shader, nullptr);
+  }
+  
+}
\ No newline at end of file
diff --git a/src/dxvk/dxvk_shader.h b/src/dxvk/dxvk_shader.h
new file mode 100644
index 000000000..e9f10a72d
--- /dev/null
+++ b/src/dxvk/dxvk_shader.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "dxvk_include.h"
+
+#include "./spirv/dxvk_spirv_code_buffer.h"
+
+namespace dxvk {
+  
+  /**
+   * \brief Shader module
+   * 
+   * Manages a Vulkan shader module. This will not
+   * perform any sort of shader compilation. Instead,
+   * the context will create pipeline objects on the
+   * fly when executing draw calls.
+   */
+  class DxvkShader : public RcObject {
+    
+  public:
+    
+    DxvkShader(
+      const Rc<vk::DeviceFn>&     vkd,
+      const SpirvCodeBuffer&      code);
+    ~DxvkShader();
+    
+    /**
+     * \brief Shader module handle
+     * \returns Shader module handle
+     */
+    VkShaderModule handle() const {
+      return m_shader;
+    }
+    
+  private:
+    
+    Rc<vk::DeviceFn>      m_vkd;
+    VkShaderModule        m_shader;
+    
+  };
+  
+}
\ No newline at end of file