diff --git a/config/Sources.cmake b/config/Sources.cmake
index 1b35d798597d0c781d5c4e90679679a83fcedcb2..e7a36ff1eb287bbbc6e3331adaa84ab476916d21 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -67,4 +67,7 @@ set(vkcv_sources
 
 		${vkcv_include}/vkcv/DescriptorConfig.hpp
 		${vkcv_source}/vkcv/DescriptorConfig.cpp
+		
+		${vkcv_source}/vkcv/SamplerManager.hpp
+		${vkcv_source}/vkcv/SamplerManager.cpp
 )
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index aa2d4a0996eb47b1c9c8a10d0ec3449775a9e504..6451d81ad3afd3f8154d778c9bceb68cdf34ba73 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -19,6 +19,7 @@
 #include "SyncResources.hpp"
 #include "Result.hpp"
 #include "vkcv/DescriptorConfig.hpp"
+#include "Sampler.hpp"
 
 namespace vkcv
 {
@@ -32,6 +33,7 @@ namespace vkcv
     class PipelineManager;
     class DescriptorManager;
     class BufferManager;
+    class SamplerManager;
     class ImageManager;
 
 	struct SubmitInfo {
@@ -70,6 +72,7 @@ namespace vkcv
         std::unique_ptr<PipelineManager> m_PipelineManager;
         std::unique_ptr<DescriptorManager> m_DescriptorManager;
         std::unique_ptr<BufferManager> m_BufferManager;
+        std::unique_ptr<SamplerManager> m_SamplerManager;
         std::unique_ptr<ImageManager> m_ImageManager;
 
 		CommandResources m_CommandResources;
@@ -168,7 +171,7 @@ namespace vkcv
         PassHandle createPass(const PassConfig &config);
 
         /**
-            * Creates a #Buffer with data-type T and @p bufferType 
+            * Creates a #Buffer with data-type T and @p bufferType
             * @param type Type of Buffer created
             * @param count Count of elements of type T
             * @param memoryType Type of Buffers memory
@@ -179,6 +182,19 @@ namespace vkcv
         	return Buffer<T>::create(m_BufferManager.get(), type, count, memoryType);
         }
         
+        /**
+         * Creates a Sampler with given attributes.
+         *
+         * @param magFilter Magnifying filter
+         * @param minFilter Minimizing filter
+         * @param mipmapMode Mipmapping filter
+         * @param addressMode Address mode
+         * @return Sampler handle
+         */
+        [[nodiscard]]
+        SamplerHandle createSampler(SamplerFilterType magFilter, SamplerFilterType minFilter,
+									SamplerMipmapMode mipmapMode, SamplerAddressMode addressMode);
+
         /**
          * Creates an #Image with a given format, width, height and depth.
          *
diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp
index 1fd6573976b1f5aab572eb982cc0c61eff01a9e9..58f795f0c99a0cd1b05045f9f401a26c0aac1b88 100644
--- a/include/vkcv/Handles.hpp
+++ b/include/vkcv/Handles.hpp
@@ -9,6 +9,7 @@
 
 namespace vkcv
 {
+	
 	class Handle {
 		friend std::ostream& operator << (std::ostream& out, const Handle& handle);
 		
@@ -64,6 +65,12 @@ namespace vkcv
 		using Handle::Handle;
 	};
 	
+	class SamplerHandle : public Handle {
+		friend class SamplerManager;
+	private:
+		using Handle::Handle;
+	};
+
 	class ImageHandle : public Handle {
 		friend class ImageManager;
 	private:
diff --git a/include/vkcv/Sampler.hpp b/include/vkcv/Sampler.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..007ed5ae4737275ddacbc5881a2c4c202b8806a4
--- /dev/null
+++ b/include/vkcv/Sampler.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+namespace vkcv {
+
+	enum class SamplerFilterType {
+		NEAREST = 1,
+		LINEAR = 2
+	};
+	
+	enum class SamplerMipmapMode {
+		NEAREST = 1,
+		LINEAR = 2
+	};
+	
+	enum class SamplerAddressMode {
+		REPEAT = 1,
+		MIRRORED_REPEAT = 2,
+		CLAMP_TO_EDGE = 3,
+		MIRROR_CLAMP_TO_EDGE = 4
+	};
+
+}
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index a71531563e6742c9c2155e2b21b18c54b769514f..d51d60e4788aeb0271d434520fad29edc3804c55 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -58,6 +58,13 @@ int main(int argc, const char** argv) {
 	m[1] = { 0, 0, 0 };
 	m[2] = { 0, 0, 0 };
 	buffer.unmap();*/
+	
+	vkcv::SamplerHandle sampler = core.createSampler(
+			vkcv::SamplerFilterType::NEAREST,
+			vkcv::SamplerFilterType::NEAREST,
+			vkcv::SamplerMipmapMode::NEAREST,
+			vkcv::SamplerAddressMode::REPEAT
+	);
 
 	std::cout << "Physical device: " << physicalDevice.getProperties().deviceName << std::endl;
 
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 902d7387c77c47946c20a7d196aa3b4892a98539..d8a67ebd2160a20a2e9b7c9b2cf81e9d6cab6b07 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -10,6 +10,7 @@
 #include "PassManager.hpp"
 #include "PipelineManager.hpp"
 #include "vkcv/BufferManager.hpp"
+#include "SamplerManager.hpp"
 #include "ImageManager.hpp"
 #include "DescriptorManager.hpp"
 #include "Surface.hpp"
@@ -95,6 +96,7 @@ namespace vkcv
             m_PipelineManager{std::make_unique<PipelineManager>(m_Context.m_Device)},
             m_DescriptorManager(std::make_unique<DescriptorManager>(m_Context.m_Device)),
 			m_BufferManager{std::unique_ptr<BufferManager>(new BufferManager())},
+			m_SamplerManager(std::unique_ptr<SamplerManager>(new SamplerManager(m_Context.m_Device))),
 			m_ImageManager{std::unique_ptr<ImageManager>(new ImageManager(*m_BufferManager))},
             m_CommandResources(commandResources),
             m_SyncResources(syncResources)
@@ -320,6 +322,11 @@ namespace vkcv
 		}
 	}
 	
+	SamplerHandle Core::createSampler(SamplerFilterType magFilter, SamplerFilterType minFilter,
+									  SamplerMipmapMode mipmapMode, SamplerAddressMode addressMode) {
+    	return m_SamplerManager->createSampler(magFilter, minFilter, mipmapMode, addressMode);
+    }
+    
 	Image Core::createImage(vk::Format format, uint32_t width, uint32_t height, uint32_t depth)
 	{
     	return Image::create(m_ImageManager.get(), format, width, height, depth);
diff --git a/src/vkcv/SamplerManager.cpp b/src/vkcv/SamplerManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7935bbc16a54f170cb38161629c109d56cf56d3c
--- /dev/null
+++ b/src/vkcv/SamplerManager.cpp
@@ -0,0 +1,127 @@
+
+#include "SamplerManager.hpp"
+#include "vkcv/Core.hpp"
+
+namespace vkcv {
+	
+	SamplerManager::SamplerManager(const vk::Device& device) noexcept :
+		m_device(device), m_samplers()
+	{}
+	
+	SamplerManager::~SamplerManager() {
+		for (uint64_t id = 0; id < m_samplers.size(); id++) {
+			destroySampler(SamplerHandle(id));
+		}
+	}
+	
+	SamplerHandle SamplerManager::createSampler(SamplerFilterType magFilter,
+												SamplerFilterType minFilter,
+												SamplerMipmapMode mipmapMode,
+												SamplerAddressMode addressMode) {
+		vk::Filter vkMagFilter;
+		vk::Filter vkMinFilter;
+		vk::SamplerMipmapMode vkMipmapMode;
+		vk::SamplerAddressMode vkAddressMode;
+		
+		switch (magFilter) {
+			case SamplerFilterType::NEAREST:
+				vkMagFilter = vk::Filter::eNearest;
+				break;
+			case SamplerFilterType::LINEAR:
+				vkMagFilter = vk::Filter::eLinear;
+				break;
+			default:
+				return SamplerHandle();
+		}
+		
+		switch (minFilter) {
+			case SamplerFilterType::NEAREST:
+				vkMinFilter = vk::Filter::eNearest;
+				break;
+			case SamplerFilterType::LINEAR:
+				vkMinFilter = vk::Filter::eLinear;
+				break;
+			default:
+				return SamplerHandle();
+		}
+		
+		switch (mipmapMode) {
+			case SamplerMipmapMode::NEAREST:
+				vkMipmapMode = vk::SamplerMipmapMode::eNearest;
+				break;
+			case SamplerMipmapMode::LINEAR:
+				vkMipmapMode = vk::SamplerMipmapMode::eLinear;
+				break;
+			default:
+				return SamplerHandle();
+		}
+		
+		switch (addressMode) {
+			case SamplerAddressMode::REPEAT:
+				vkAddressMode = vk::SamplerAddressMode::eRepeat;
+				break;
+			case SamplerAddressMode::MIRRORED_REPEAT:
+				vkAddressMode = vk::SamplerAddressMode::eMirroredRepeat;
+				break;
+			case SamplerAddressMode::CLAMP_TO_EDGE:
+				vkAddressMode = vk::SamplerAddressMode::eClampToEdge;
+				break;
+			case SamplerAddressMode::MIRROR_CLAMP_TO_EDGE:
+				vkAddressMode = vk::SamplerAddressMode::eMirrorClampToEdge;
+				break;
+			default:
+				return SamplerHandle();
+		}
+		
+		const vk::SamplerCreateInfo samplerCreateInfo (
+				vk::SamplerCreateFlags(),
+				vkMagFilter,
+				vkMinFilter,
+				vkMipmapMode,
+				vkAddressMode,
+				vkAddressMode,
+				vkAddressMode,
+				0.0f,
+				false,
+				16.0f,
+				false,
+				vk::CompareOp::eAlways,
+				0.0f,
+				1.0f,
+				vk::BorderColor::eIntOpaqueBlack,
+				false
+		);
+		
+		const vk::Sampler sampler = m_device.createSampler(samplerCreateInfo);
+		
+		const uint64_t id = m_samplers.size();
+		m_samplers.push_back(sampler);
+		return SamplerHandle(id);
+	}
+	
+	vk::Sampler SamplerManager::getVulkanSampler(const SamplerHandle &handle) const {
+		const uint64_t id = handle.getId();
+		
+		if (id >= m_samplers.size()) {
+			return nullptr;
+		}
+		
+		return m_samplers[id];
+	}
+	
+	void SamplerManager::destroySampler(const SamplerHandle &handle) {
+		const uint64_t id = handle.getId();
+		
+		if (id >= m_samplers.size()) {
+			return;
+		}
+		
+		auto& sampler = m_samplers[id];
+		
+		if (sampler) {
+			m_device.destroySampler(sampler);
+			sampler = nullptr;
+		}
+	}
+
+}
diff --git a/src/vkcv/SamplerManager.hpp b/src/vkcv/SamplerManager.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..41f58b2f33daaf8b08c785c05c7f14184cf47958
--- /dev/null
+++ b/src/vkcv/SamplerManager.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <vector>
+#include <vulkan/vulkan.hpp>
+
+#include "vkcv/Handles.hpp"
+#include "vkcv/Sampler.hpp"
+
+namespace vkcv {
+	
+	class Core;
+	
+	class SamplerManager {
+		friend class Core;
+	private:
+		vk::Device m_device;
+		std::vector<vk::Sampler> m_samplers;
+		
+		explicit SamplerManager(const vk::Device& device) noexcept;
+		
+	public:
+		~SamplerManager();
+		
+		SamplerManager(const SamplerManager& other) = delete;
+		SamplerManager(SamplerManager&& other) = delete;
+		
+		SamplerManager& operator=(const SamplerManager& other) = delete;
+		SamplerManager& operator=(SamplerManager&& other) = delete;
+		
+		SamplerHandle createSampler(SamplerFilterType magFilter,
+							  		SamplerFilterType minFilter,
+							  		SamplerMipmapMode mipmapMode,
+							  		SamplerAddressMode addressMode);
+		
+		[[nodiscard]]
+		vk::Sampler getVulkanSampler(const SamplerHandle& handle) const;
+		
+		void destroySampler(const SamplerHandle& handle);
+	
+	};
+	
+}