diff --git a/.github/workflows/MacOs.yml b/.github/workflows/MacOs.yml
index 1091706..588d501 100644
--- a/.github/workflows/MacOs.yml
+++ b/.github/workflows/MacOs.yml
@@ -19,8 +19,7 @@ jobs:
           { tool: apple-clang },
           { tool: gcc, ver: 10 },
           { tool: gcc, ver: 11 },
-          { tool: gcc, ver: 12 },
-          { tool: gcc, ver: 13 } ]
+          { tool: gcc, ver: 12 } ]
         build_type: [ Release ]
         os: [ macos-12 ]
         std: [ 17 ]
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9e5854f..0a394f1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.15.0)
 set(_7BIT_DI_LIBRARY 7bitDI)
 
 set(_7BIT_DI_VERSION_MAJOR 3)
-set(_7BIT_DI_VERSION_MINOR 2)
+set(_7BIT_DI_VERSION_MINOR 3)
 set(_7BIT_DI_VERSION_PATCH 0)
 
 set(_7BIT_DI_VERSION ${_7BIT_DI_VERSION_MAJOR}.${_7BIT_DI_VERSION_MINOR}.${_7BIT_DI_VERSION_PATCH})
diff --git a/Docs/advanced-guides.rst b/Docs/advanced-guides.rst
index 0eeae13..b26ea9a 100644
--- a/Docs/advanced-guides.rst
+++ b/Docs/advanced-guides.rst
@@ -11,5 +11,4 @@ Advanced Guides
    advanced-guides/using-aliases
    advanced-guides/register-utility-class
    advanced-guides/injected-utility-class
-   advanced-guides/configuring-service-provider
    advanced-guides/building-library
diff --git a/Docs/advanced-guides/injected-utility-class.rst b/Docs/advanced-guides/injected-utility-class.rst
index 5ceaf89..36f0558 100644
--- a/Docs/advanced-guides/injected-utility-class.rst
+++ b/Docs/advanced-guides/injected-utility-class.rst
@@ -1,16 +1,16 @@
 Injected Utility Class
 ========================================
 
-Library provides also Injected_ utility class.
-This base class has inject() method that can be used to inject services in simple inline way, also
-there are InjectedSingleton, InjectedScoped and InjectedTransient base classes that are inheriting
-from Injected and Registered classes to combine these two features. Injected class has also method
-getProvider(), raw provider can be used to get keyed services for example.
+The library provides also Injected_ utility class.
+This base class has inject() method that can be used to inject services in a simple inline way, also
+there are InjectedSingleton, InjectedScoped and InjectedTransient base classes that inherit
+from Injected and Registered classes to combine these two features. The injected class has also a method
+getProvider(), the raw provider can be used to get keyed services for example.
 
 .. _Injected: ../reference/di/utils/injected.html
 
 .. note::
-   Class should inherit Injected constructor with 'using Injected::Injected;' in public section
+   The class should inherit Injected constructor with 'using Injected::Injected;' in the public section
 
 .. literalinclude:: ../../Examples/Guides/InjectedUtilityClass.cpp
    :caption: Examples/Guides/InjectedUtilityClass
diff --git a/Docs/advanced-guides/register-utility-class.rst b/Docs/advanced-guides/register-utility-class.rst
index ba17282..079de67 100644
--- a/Docs/advanced-guides/register-utility-class.rst
+++ b/Docs/advanced-guides/register-utility-class.rst
@@ -1,13 +1,13 @@
 Register Utility Class
 ========================================
 
-Library provides simple template RegisterService_ utility class.
-This base class can be used to automatically register class in service collection with use of specialised TRegisterer.
+The library provides a simple template RegisterService_ utility class.
+This base class can be used to automatically register class in service collection with the use of a specialized TRegisterer.
 There are already created aliases RegisterSingleton_, RegisterScoped_, RegisterTransient_ that are registering services
 in GlobalServices_ singleton.
 
 .. note::
-   Class should inherit Injected constructor with 'using Injected::Injected;' in public section
+   The class should inherit Injected constructor with 'using Injected::Injected;' in the public section
 
 .. _RegisterService: ../reference/di/utils/register.html
 .. _RegisterSingleton: ../reference/di/utils/register.html
diff --git a/Docs/advanced-guides/using-aliases.rst b/Docs/advanced-guides/using-aliases.rst
index 5d82c33..4a2d9bb 100644
--- a/Docs/advanced-guides/using-aliases.rst
+++ b/Docs/advanced-guides/using-aliases.rst
@@ -2,11 +2,11 @@ Using Aliases
 ========================================
 
 With the use of aliases, one service can be injected through its multiple base classes, also aliases can be chained.
-In case of injecting multiple aliases all real services will be fetched.
+In case of injecting multiple aliases, all real services will be fetched.
 
 .. warning::
    Using aliases is resource intensive, especially for injecting transient and multiple services, provider recursively
-   traverses through aliases chain to find proper service. Mixing scoped and singleton aliases for same base type will
+   traverses through the aliases chain to find the proper service. Mixing scoped and singleton aliases for the same base type will
    lead to undefined behavior
 
 .. literalinclude:: ../../Examples/Guides/ServiceAliases.cpp
diff --git a/Docs/basic-guides.rst b/Docs/basic-guides.rst
index 81c6ed4..62380f3 100644
--- a/Docs/basic-guides.rst
+++ b/Docs/basic-guides.rst
@@ -12,3 +12,4 @@ Basic Guides
    basic-guides/injecting-multiple-services
    basic-guides/injection-rules
    basic-guides/injecting-service-provider
+   basic-guides/configuring-service-provider
diff --git a/Docs/advanced-guides/configuring-service-provider.rst b/Docs/basic-guides/configuring-service-provider.rst
similarity index 91%
rename from Docs/advanced-guides/configuring-service-provider.rst
rename to Docs/basic-guides/configuring-service-provider.rst
index c90fca8..11d1f67 100644
--- a/Docs/advanced-guides/configuring-service-provider.rst
+++ b/Docs/basic-guides/configuring-service-provider.rst
@@ -10,8 +10,8 @@ read comment documentation for details:
    :caption: Include/SevenBit/DI/ServiceProviderOptions.hpp
    :language: C++
 
-Pass the custom options to the ServiceCollection buildServiceProvider method to change produced
-service provider behaviour
+Pass the custom options to the ServiceCollection buildServiceProvider method to change the produced
+service provider behavior
 
 .. literalinclude:: ../../Examples/Guides/ConfiguredServiceProvider.cpp
    :caption: Examples/Guides/ConfiguredServiceProvider
diff --git a/Docs/conf.py b/Docs/conf.py
index 5ec2320..e646c4f 100644
--- a/Docs/conf.py
+++ b/Docs/conf.py
@@ -12,7 +12,7 @@ def createIfNotExists(path):
 project = "7bitDI"
 copyright = "2023, 7BitCoder Sylwester Dawida"
 author = "Sylwester Dawida"
-version = "3.2.0"
+version = "3.3.0"
 
 extensions = [
     "sphinx.ext.autodoc",
diff --git a/Docs/getting-started.rst b/Docs/getting-started.rst
index 79fb6e7..b942949 100644
--- a/Docs/getting-started.rst
+++ b/Docs/getting-started.rst
@@ -1,6 +1,16 @@
 Getting Started
 ==========================
 
+Main Features
+--------------------
+
+* Implementation separation
+* Multiple implementations
+* Keyed services
+* Service aliases
+* Thread safe
+* Strong destruction order
+
 Supported Platforms
 --------------------
 
@@ -27,8 +37,8 @@ Installation
 **There are a few ways of installation:**
 
 
-#. Using Cmake fetch content api - Recommended
-    Update CMakeLists.txt file with following code
+#. Using Cmake fetch content API - Recommended
+    Update CMakeLists.txt file with the following code
 
     .. code-block:: Cmake
 
@@ -36,7 +46,7 @@ Installation
         FetchContent_Declare(
                 7bitDI
                 GIT_REPOSITORY https://github.com/7bitcoder/7bitDI.git
-                GIT_TAG v3.2.0
+                GIT_TAG v3.3.0
         )
         FetchContent_MakeAvailable(7bitDI)
 
@@ -48,7 +58,7 @@ Installation
     .. code-block:: Txt
 
         [requires]
-        7bitdi/3.2.0
+        7bitdi/3.3.0
     
     change the version to newer if available, then run the command:
 
diff --git a/Examples/Guides/ConfiguredServiceProvider.cpp b/Examples/Guides/ConfiguredServiceProvider.cpp
index 2b7c8c7..17a67a4 100644
--- a/Examples/Guides/ConfiguredServiceProvider.cpp
+++ b/Examples/Guides/ConfiguredServiceProvider.cpp
@@ -39,6 +39,7 @@ int main()
     options.strongDestructionOrder = true;
     options.prebuildSingletons = true;
     options.checkServiceGlobalUniqueness = false;
+    options.threadSafe = true;
 
     ServiceProvider provider = ServiceCollection{}
                                    .addSingleton<IService, Service>()
diff --git a/Include/SevenBit/DI/CmakeDef.hpp b/Include/SevenBit/DI/CmakeDef.hpp
index 9dcd81a..56f8e83 100644
--- a/Include/SevenBit/DI/CmakeDef.hpp
+++ b/Include/SevenBit/DI/CmakeDef.hpp
@@ -13,5 +13,5 @@
 #endif
 
 #define _7BIT_DI_VERSION_MAJOR 3
-#define _7BIT_DI_VERSION_MINOR 2
+#define _7BIT_DI_VERSION_MINOR 3
 /* #undef _7BIT_DI_VERSION_PATCH */
diff --git a/Include/SevenBit/DI/Details/Containers/Impl/ServiceInstancesMap.hpp b/Include/SevenBit/DI/Details/Containers/Impl/ServiceInstancesMap.hpp
index df48a37..1a8d494 100644
--- a/Include/SevenBit/DI/Details/Containers/Impl/ServiceInstancesMap.hpp
+++ b/Include/SevenBit/DI/Details/Containers/Impl/ServiceInstancesMap.hpp
@@ -42,9 +42,9 @@ namespace sb::di::details
         {
             for (auto it = _constructionOrder.rbegin(); it != _constructionOrder.rend(); ++it)
             {
-                if (const auto list = findInstances(*it))
+                if (const auto listPtr = findInstances(*it))
                 {
-                    list->clear();
+                    listPtr->clear();
                 }
             }
         }
diff --git a/Include/SevenBit/DI/Details/Core/IServiceInstanceProviderRoot.hpp b/Include/SevenBit/DI/Details/Core/IServiceInstanceProviderRoot.hpp
index 2005116..67aab32 100644
--- a/Include/SevenBit/DI/Details/Core/IServiceInstanceProviderRoot.hpp
+++ b/Include/SevenBit/DI/Details/Core/IServiceInstanceProviderRoot.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <mutex>
+
 #include "SevenBit/DI/LibraryConfig.hpp"
 
 #include "SevenBit/DI/Details/Containers/ServiceDescriptorsMap.hpp"
@@ -16,6 +18,8 @@ namespace sb::di::details
 
         virtual ServiceInstancesCreator &getRootCreator() = 0;
 
+        virtual std::recursive_mutex *tryGetSyncMutex() = 0;
+
         virtual ~IServiceInstanceProviderRoot() = default;
     };
 } // namespace sb::di::details
diff --git a/Include/SevenBit/DI/Details/Core/Impl/ServiceInstanceProvider.hpp b/Include/SevenBit/DI/Details/Core/Impl/ServiceInstanceProvider.hpp
index 9d39b3c..365eb3f 100644
--- a/Include/SevenBit/DI/Details/Core/Impl/ServiceInstanceProvider.hpp
+++ b/Include/SevenBit/DI/Details/Core/Impl/ServiceInstanceProvider.hpp
@@ -27,7 +27,7 @@ namespace sb::di::details
 
     INLINE IServiceInstanceProvider::Ptr ServiceInstanceProvider::createScope() const
     {
-        return std::make_unique<ServiceInstanceProvider>(_root, _options);
+        return std::make_unique<ServiceInstanceProvider>(_root, getOptions());
     }
 
     INLINE const ServiceInstance &ServiceInstanceProvider::getInstance(const ServiceId &id)
diff --git a/Include/SevenBit/DI/Details/Core/Impl/ServiceInstanceProviderRoot.hpp b/Include/SevenBit/DI/Details/Core/Impl/ServiceInstanceProviderRoot.hpp
index f684349..05de8bb 100644
--- a/Include/SevenBit/DI/Details/Core/Impl/ServiceInstanceProviderRoot.hpp
+++ b/Include/SevenBit/DI/Details/Core/Impl/ServiceInstanceProviderRoot.hpp
@@ -10,12 +10,16 @@ namespace sb::di::details
         : ServiceInstanceProvider(*this, options), _descriptorsMap(options.checkServiceGlobalUniqueness),
           _singletons(options.strongDestructionOrder)
     {
-        _descriptorsMap.seal();
     }
 
     INLINE void ServiceInstanceProviderRoot::init(ServiceProvider &serviceProvider)
     {
         ServiceInstanceProvider::init(serviceProvider);
+        _descriptorsMap.seal();
+        if (getOptions().threadSafe)
+        {
+            _mutex = std::make_unique<std::recursive_mutex>();
+        }
         if (getOptions().prebuildSingletons)
         {
             prebuildSingletons();
diff --git a/Include/SevenBit/DI/Details/Core/ServiceInstanceProvider.hpp b/Include/SevenBit/DI/Details/Core/ServiceInstanceProvider.hpp
index 04ace73..33ea0cb 100644
--- a/Include/SevenBit/DI/Details/Core/ServiceInstanceProvider.hpp
+++ b/Include/SevenBit/DI/Details/Core/ServiceInstanceProvider.hpp
@@ -18,9 +18,9 @@ namespace sb::di::details
     class EXPORT ServiceInstanceProvider : public IServiceInstanceProvider
     {
         ServiceProviderOptions _options;
+        IServiceInstanceProviderRoot &_root;
         ServiceInstancesCreator _instancesCreator;
         ServiceAliasesCreator _aliasesCreator;
-        IServiceInstanceProviderRoot &_root;
         ServiceInstancesMap _scoped;
 
       public:
@@ -39,6 +39,8 @@ namespace sb::di::details
 
         [[nodiscard]] IServiceInstanceProvider::Ptr createScope() const override;
 
+        std::recursive_mutex *tryGetSyncMutex() override { return _root.tryGetSyncMutex(); }
+
         const ServiceInstance &getInstance(const TypeId serviceTypeId) override
         {
             return getInstance(ServiceId{serviceTypeId});
diff --git a/Include/SevenBit/DI/Details/Core/ServiceInstanceProviderRoot.hpp b/Include/SevenBit/DI/Details/Core/ServiceInstanceProviderRoot.hpp
index d51ac52..a051681 100644
--- a/Include/SevenBit/DI/Details/Core/ServiceInstanceProviderRoot.hpp
+++ b/Include/SevenBit/DI/Details/Core/ServiceInstanceProviderRoot.hpp
@@ -13,6 +13,7 @@ namespace sb::di::details
     {
         ServiceDescriptorsMap _descriptorsMap;
         ServiceInstancesMap _singletons;
+        std::unique_ptr<std::recursive_mutex> _mutex;
 
       public:
         using Ptr = std::unique_ptr<ServiceInstanceProviderRoot>;
@@ -26,7 +27,6 @@ namespace sb::di::details
               _descriptorsMap(begin, end, options.checkServiceGlobalUniqueness),
               _singletons(options.strongDestructionOrder)
         {
-            _descriptorsMap.seal();
         }
 
         void init(ServiceProvider &serviceProvider) override;
@@ -37,6 +37,8 @@ namespace sb::di::details
 
         ServiceInstancesCreator &getRootCreator() override { return getCreator(); }
 
+        std::recursive_mutex *tryGetSyncMutex() override { return _mutex.get(); }
+
       private:
         void prebuildSingletons();
     };
diff --git a/Include/SevenBit/DI/IServiceInstanceProvider.hpp b/Include/SevenBit/DI/IServiceInstanceProvider.hpp
index d9d5015..2ea20cd 100644
--- a/Include/SevenBit/DI/IServiceInstanceProvider.hpp
+++ b/Include/SevenBit/DI/IServiceInstanceProvider.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <memory>
+#include <mutex>
 #include <optional>
 #include <string_view>
 
@@ -29,6 +30,13 @@ namespace sb::di
          */
         [[nodiscard]] virtual Ptr createScope() const = 0;
 
+        /**
+         * @brief Get sync mutex
+         * @details Mutex can be used to synchronize service accesses between threads, can be null if synchronization is
+         * not needed
+         */
+        virtual std::recursive_mutex *tryGetSyncMutex() = 0;
+
         /**
          * @brief Returns service instance reference, might throw exception
          * @details If service was not registered or was registered as transient, method throws exception
diff --git a/Include/SevenBit/DI/ServiceCollection.hpp b/Include/SevenBit/DI/ServiceCollection.hpp
index 502f5b8..cfe4bc4 100644
--- a/Include/SevenBit/DI/ServiceCollection.hpp
+++ b/Include/SevenBit/DI/ServiceCollection.hpp
@@ -476,8 +476,8 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.add<TestClass>(ServiceLifeTimes::Scoped, "key");
-         * ServiceCollection{}.add<BaseClass, ImplementationClass>(ServiceLifeTimes::Transient, "key");
+         * ServiceCollection{}.addKeyed<TestClass>(ServiceLifeTimes::Scoped, "key");
+         * ServiceCollection{}.addKeyed<BaseClass, ImplementationClass>(ServiceLifeTimes::Transient, "key");
          * @endcode
          */
         template <class TService, class TImplementation = TService>
@@ -515,8 +515,8 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.addSingleton<TestClass>("key");
-         * ServiceCollection{}.addSingleton<BaseClass, ImplementationClass>("key");
+         * ServiceCollection{}.addKeyedSingleton<TestClass>("key");
+         * ServiceCollection{}.addKeyedSingleton<BaseClass, ImplementationClass>("key");
          * @endcode
          */
         template <class TService, class TImplementation = TService>
@@ -554,8 +554,8 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.addScoped<TestClass>("key");
-         * ServiceCollection{}.addScoped<BaseClass, ImplementationClass>("key");
+         * ServiceCollection{}.addKeyedScoped<TestClass>("key");
+         * ServiceCollection{}.addKeyedScoped<BaseClass, ImplementationClass>("key");
          * @endcode
          */
         template <class TService, class TImplementation = TService>
@@ -593,8 +593,8 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.addTransient<TestClass>("key");
-         * ServiceCollection{}.addTransient<BaseClass, ImplementationClass>("key");
+         * ServiceCollection{}.addKeyedTransient<TestClass>("key");
+         * ServiceCollection{}.addKeyedTransient<BaseClass, ImplementationClass>("key");
          * @endcode
          */
         template <class TService, class TImplementation = TService>
@@ -629,7 +629,7 @@ namespace sb::di
          * Example:
          * @code{.cpp}
          * TestClass test;
-         * ServiceCollection{}.addSingleton("key", &test);
+         * ServiceCollection{}.addKeyedSingleton("key", &test);
          * @endcode
          */
         template <class TService> ServiceCollection &addKeyedSingleton(std::string serviceKey, TService *service)
@@ -667,7 +667,7 @@ namespace sb::di
          * Example:
          * @code{.cpp}
          * ImplementationClass implementation;
-         * ServiceCollection{}.addSingleton<BaseClass>("key", &implementation);
+         * ServiceCollection{}.addKeyedSingleton<BaseClass>("key", &implementation);
          * @endcode
          */
         template <class TService, class TImplementation>
@@ -710,7 +710,7 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.add<BaseClass>(ServiceLifeTimes::Scoped, "key",
+         * ServiceCollection{}.addKeyed<BaseClass>(ServiceLifeTimes::Scoped, "key",
          *       []() { return std::make_unique<ImplementationClass>(); });
          * @endcode
          */
@@ -750,7 +750,8 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.addSingleton<BaseClass>("key", []() { return std::make_unique<ImplementationClass>(); });
+         * ServiceCollection{}.addKeyedSingleton<BaseClass>("key", []() { return
+         * std::make_unique<ImplementationClass>(); });
          * @endcode
          */
         template <class TService, class FactoryFcn>
@@ -789,7 +790,8 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.addScoped<BaseClass>("key", []() { return std::make_unique<ImplementationClass>(); });
+         * ServiceCollection{}.addKeyedScoped<BaseClass>("key", []() { return std::make_unique<ImplementationClass>();
+         * });
          * @endcode
          */
         template <class TService, class FactoryFcn>
@@ -828,7 +830,8 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.addTransient<BaseClass>("key", []() { return std::make_unique<ImplementationClass>(); });
+         * ServiceCollection{}.addKeyedTransient<BaseClass>("key", []() { return
+         * std::make_unique<ImplementationClass>(); });
          * @endcode
          */
         template <class TService, class FactoryFcn>
@@ -867,7 +870,8 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.add(ServiceLifeTimes::Transient, "key", []() { return std::make_unique<TestClass>(); });
+         * ServiceCollection{}.addKeyed(ServiceLifeTimes::Transient, "key", []() { return std::make_unique<TestClass>();
+         * });
          * @endcode
          */
         template <class FactoryFcn>
@@ -904,7 +908,7 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.addSingleton("key", []() { return std::make_unique<TestClass>(); });
+         * ServiceCollection{}.addKeyedSingleton("key", []() { return std::make_unique<TestClass>(); });
          * @endcode
          */
         template <class FactoryFcn> ServiceCollection &addKeyedSingleton(std::string serviceKey, FactoryFcn factory)
@@ -940,7 +944,7 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.addScoped("key", []() { return std::make_unique<TestClass>(); });
+         * ServiceCollection{}.addKeyedScoped("key", []() { return std::make_unique<TestClass>(); });
          * @endcode
          */
         template <class FactoryFcn> ServiceCollection &addKeyedScoped(std::string serviceKey, FactoryFcn factory)
@@ -976,7 +980,7 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.addTransient("key", []() { return std::make_unique<TestClass>(); });
+         * ServiceCollection{}.addKeyedTransient("key", []() { return std::make_unique<TestClass>(); });
          * @endcode
          */
         template <class FactoryFcn> ServiceCollection &addKeyedTransient(std::string serviceKey, FactoryFcn factory)
@@ -1026,7 +1030,7 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.addAlias<AliasClass, ServiceClass>("aliasKey", "key");
+         * ServiceCollection{}.addKeyedAlias<AliasClass, ServiceClass>("aliasKey", "key");
          * @endcode
          */
         template <class TAlias, class TService>
@@ -1045,7 +1049,7 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * ServiceCollection{}.addAlias<AliasClass, ServiceClass>("aliasKey");
+         * ServiceCollection{}.addKeyedAlias<AliasClass, ServiceClass>("aliasKey");
          * @endcode
          */
         template <class TAlias, class TService> ServiceCollection &addKeyedAlias(std::string serviceAliasKey)
diff --git a/Include/SevenBit/DI/ServiceProvider.hpp b/Include/SevenBit/DI/ServiceProvider.hpp
index 83c8345..8932be4 100644
--- a/Include/SevenBit/DI/ServiceProvider.hpp
+++ b/Include/SevenBit/DI/ServiceProvider.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <memory>
+#include <mutex>
 #include <type_traits>
 #include <vector>
 
@@ -15,37 +16,37 @@ namespace sb::di
     class ServiceProvider
     {
         IServiceInstanceProvider::Ptr _instanceProvider;
+        std::recursive_mutex *_syncMutex = nullptr;
 
       public:
         using Ptr = std::unique_ptr<ServiceProvider>;
 
         /**
          * @brief Constructs service provider with specified instance provider
+         * @details If service instance provider is nullptr, constructor throws exception
+         * @throws sb::di::NullPointerException
          */
         explicit ServiceProvider(IServiceInstanceProvider::Ptr instanceProvider)
             : _instanceProvider(std::move(instanceProvider))
         {
             details::Require::notNull(_instanceProvider);
-            getInstanceProvider().init(*this);
+            _instanceProvider->init(*this);
+            _syncMutex = _instanceProvider->tryGetSyncMutex();
         }
 
-        ServiceProvider(const ServiceProvider &parent) = delete;
+        ServiceProvider(const ServiceProvider &) = delete;
         ServiceProvider(ServiceProvider &&) = delete;
 
-        ServiceProvider &operator=(const ServiceProvider &parent) = delete;
-        ServiceProvider &operator=(ServiceProvider &&parent) = delete;
+        ServiceProvider &operator=(const ServiceProvider &) = delete;
+        ServiceProvider &operator=(ServiceProvider &&) = delete;
 
         /**
          * @brief Returns inner service instance provider
-         * @details If service instance provider is nullptr, method throws exception
-         * @throws sb::di::NullPointerException
          */
         [[nodiscard]] const IServiceInstanceProvider &getInstanceProvider() const { return *_instanceProvider; }
 
         /**
          * @brief Returns inner service instance provider
-         * @details If service instance provider is nullptr, method throws exception
-         * @throws sb::di::NullPointerException
          */
         IServiceInstanceProvider &getInstanceProvider() { return *_instanceProvider; }
 
@@ -96,12 +97,14 @@ namespace sb::di
          */
         template <class TService> TService *tryGetService()
         {
-            if (const auto instancePtr = getInstanceProvider().tryGetInstance(typeid(TService));
-                instancePtr && *instancePtr)
-            {
-                return instancePtr->getAs<TService>();
-            }
-            return nullptr;
+            return safeAction([&]() -> TService * {
+                if (const auto instancePtr = getInstanceProvider().tryGetInstance(typeid(TService));
+                    instancePtr && *instancePtr)
+                {
+                    return instancePtr->getAs<TService>();
+                }
+                return nullptr;
+            });
         }
 
         /**
@@ -111,19 +114,21 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * auto provider = ServiceCollection{}.addScoped<TestClass>().buildServiceProvider();
+         * auto provider = ServiceCollection{}.addKeyedScoped<TestClass>("key").buildServiceProvider();
          *
-         * TestClass* service = provider.tryGetService<TestClass>();
+         * TestClass* service = provider.tryGetKeyedService<TestClass>("key");
          * @endcode
          */
         template <class TService> TService *tryGetKeyedService(const std::string_view serviceKey)
         {
-            if (const auto instancePtr = getInstanceProvider().tryGetKeyedInstance(typeid(TService), serviceKey);
-                instancePtr && *instancePtr)
-            {
-                return instancePtr->getAs<TService>();
-            }
-            return nullptr;
+            return safeAction([&]() -> TService * {
+                if (const auto instancePtr = getInstanceProvider().tryGetKeyedInstance(typeid(TService), serviceKey);
+                    instancePtr && *instancePtr)
+                {
+                    return instancePtr->getAs<TService>();
+                }
+                return nullptr;
+            });
         }
 
         /**
@@ -140,9 +145,11 @@ namespace sb::di
          */
         template <class TService> TService &getService()
         {
-            auto &instance = getInstanceProvider().getInstance(typeid(TService));
-            details::RequireInstance::valid(instance);
-            return *instance.getAs<TService>();
+            return *safeAction([&]() -> TService * {
+                auto &instance = getInstanceProvider().getInstance(typeid(TService));
+                details::RequireInstance::valid(instance);
+                return instance.getAs<TService>();
+            });
         }
 
         /**
@@ -153,16 +160,18 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * auto provider = ServiceCollection{}.addScoped<TestClass>().buildServiceProvider();
+         * auto provider = ServiceCollection{}.addKeyedScoped<TestClass>("key").buildServiceProvider();
          *
-         * TestClass& service = provider.getService<TestClass>();
+         * TestClass& service = provider.getKeyedService<TestClass>("key");
          * @endcode
          */
         template <class TService> TService &getKeyedService(const std::string_view serviceKey)
         {
-            auto &instance = getInstanceProvider().getKeyedInstance(typeid(TService), serviceKey);
-            details::RequireInstance::valid(instance);
-            return *instance.getAs<TService>();
+            return *safeAction([&]() -> TService * {
+                auto &instance = getInstanceProvider().getKeyedInstance(typeid(TService), serviceKey);
+                details::RequireInstance::valid(instance);
+                return instance.getAs<TService>();
+            });
         }
 
         /**
@@ -181,14 +190,16 @@ namespace sb::di
          */
         template <class TService> std::vector<TService *> getServices()
         {
-            if (auto instancesPtr = getInstanceProvider().tryGetInstances(typeid(TService)))
-            {
-                return instancesPtr->map([](const ServiceInstance &instance) {
-                    details::RequireInstance::valid(instance);
-                    return instance.getAs<TService>();
-                });
-            }
-            return {};
+            return safeAction([&]() -> std::vector<TService *> {
+                if (auto instancesPtr = getInstanceProvider().tryGetInstances(typeid(TService)))
+                {
+                    return instancesPtr->map([](const ServiceInstance &instance) {
+                        details::RequireInstance::valid(instance);
+                        return instance.getAs<TService>();
+                    });
+                }
+                return {};
+            });
         }
 
         /**
@@ -199,23 +210,25 @@ namespace sb::di
          * Example:
          * @code{.cpp}
          * auto provider = ServiceCollection{}
-         *              .addScoped<ITestClass, TestClass1>()
-         *              .addScoped<ITestClass, TestClass2>()
+         *              .addKeyedScoped<ITestClass, TestClass1>("key")
+         *              .addKeyedScoped<ITestClass, TestClass2>("key")
          *              .buildServiceProvider();
          *
-         * std::vector<ITestClass *> services = provider.getServices<ITestClass>();
+         * std::vector<ITestClass *> services = provider.getKeyedServices<ITestClass>("key");
          * @endcode
          */
         template <class TService> std::vector<TService *> getKeyedServices(const std::string_view serviceKey)
         {
-            if (auto instancesPtr = getInstanceProvider().tryGetKeyedInstances(typeid(TService), serviceKey))
-            {
-                return instancesPtr->map([](const ServiceInstance &instance) {
-                    details::RequireInstance::valid(instance);
-                    return instance.getAs<TService>();
-                });
-            }
-            return {};
+            return safeAction([&]() -> std::vector<TService *> {
+                if (auto instancesPtr = getInstanceProvider().tryGetKeyedInstances(typeid(TService), serviceKey))
+                {
+                    return instancesPtr->map([](const ServiceInstance &instance) {
+                        details::RequireInstance::valid(instance);
+                        return instance.getAs<TService>();
+                    });
+                }
+                return {};
+            });
         }
 
         /**
@@ -231,11 +244,13 @@ namespace sb::di
          */
         template <class TService> std::unique_ptr<TService> tryCreateService()
         {
-            if (auto instance = getInstanceProvider().tryCreateInstance(typeid(TService)))
-            {
-                return instance.moveOutAsUniquePtr<TService>();
-            }
-            return nullptr;
+            return safeAction([&]() -> std::unique_ptr<TService> {
+                if (auto instance = getInstanceProvider().tryCreateInstance(typeid(TService)))
+                {
+                    return instance.moveOutAsUniquePtr<TService>();
+                }
+                return nullptr;
+            });
         }
 
         /**
@@ -245,18 +260,20 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * auto provider = ServiceCollection{}.addTransient<TestClass>().buildServiceProvider();
+         * auto provider = ServiceCollection{}.addKeyedTransient<TestClass>("key").buildServiceProvider();
          *
-         * std::unique_ptr<TestClass> service = provider.tryCreateService<TestClass>();
+         * std::unique_ptr<TestClass> service = provider.tryCreateKeyedService<TestClass>("key");
          * @endcode
          */
         template <class TService> std::unique_ptr<TService> tryCreateKeyedService(const std::string_view serviceKey)
         {
-            if (auto instance = getInstanceProvider().tryCreateKeyedInstance(typeid(TService), serviceKey))
-            {
-                return instance.moveOutAsUniquePtr<TService>();
-            }
-            return nullptr;
+            return safeAction([&]() -> std::unique_ptr<TService> {
+                if (auto instance = getInstanceProvider().tryCreateKeyedInstance(typeid(TService), serviceKey))
+                {
+                    return instance.moveOutAsUniquePtr<TService>();
+                }
+                return nullptr;
+            });
         }
 
         /**
@@ -273,9 +290,11 @@ namespace sb::di
          */
         template <class TService> std::unique_ptr<TService> createService()
         {
-            auto instance = getInstanceProvider().createInstance(typeid(TService));
-            details::RequireInstance::valid(instance);
-            return instance.moveOutAsUniquePtr<TService>();
+            return safeAction([&]() -> std::unique_ptr<TService> {
+                auto instance = getInstanceProvider().createInstance(typeid(TService));
+                details::RequireInstance::valid(instance);
+                return instance.moveOutAsUniquePtr<TService>();
+            });
         }
 
         /**
@@ -286,16 +305,18 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * auto provider = ServiceCollection{}.addTransient<TestClass>().buildServiceProvider();
+         * auto provider = ServiceCollection{}.addKeyedTransient<TestClass>("key").buildServiceProvider();
          *
-         * std::unique_ptr<TestClass> service = provider.createService<TestClass>();
+         * std::unique_ptr<TestClass> service = provider.createKeyedService<TestClass>("key");
          * @endcode
          */
         template <class TService> std::unique_ptr<TService> createKeyedService(const std::string_view serviceKey)
         {
-            auto instance = getInstanceProvider().createKeyedInstance(typeid(TService), serviceKey);
-            details::RequireInstance::valid(instance);
-            return instance.moveOutAsUniquePtr<TService>();
+            return safeAction([&]() -> std::unique_ptr<TService> {
+                auto instance = getInstanceProvider().createKeyedInstance(typeid(TService), serviceKey);
+                details::RequireInstance::valid(instance);
+                return instance.moveOutAsUniquePtr<TService>();
+            });
         }
 
         /**
@@ -312,16 +333,18 @@ namespace sb::di
          */
         template <class TService> TService createServiceInPlace()
         {
-            auto instance = getInstanceProvider().createInstanceInPlace(typeid(TService));
-            details::RequireInstance::valid(instance);
-            if constexpr (std::is_move_constructible_v<TService>)
-            {
-                return instance.moveOutAs<TService>();
-            }
-            else
-            {
-                return instance.copyAs<TService>();
-            }
+            return safeAction([&]() -> TService {
+                auto instance = getInstanceProvider().createInstanceInPlace(typeid(TService));
+                details::RequireInstance::valid(instance);
+                if constexpr (std::is_move_constructible_v<TService>)
+                {
+                    return instance.moveOutAs<TService>();
+                }
+                else
+                {
+                    return instance.copyAs<TService>();
+                }
+            });
         }
 
         /**
@@ -332,23 +355,25 @@ namespace sb::di
          *
          * Example:
          * @code{.cpp}
-         * auto provider = ServiceCollection{}.addTransient<TestClass>().buildServiceProvider();
+         * auto provider = ServiceCollection{}.addKeyedTransient<TestClass>("key").buildServiceProvider();
          *
-         * TestClass service = provider.createServiceInPlace<TestClass>();
+         * TestClass service = provider.createKeyedServiceInPlace<TestClass>("key");
          * @endcode
          */
         template <class TService> TService createKeyedServiceInPlace(const std::string_view serviceKey)
         {
-            auto instance = getInstanceProvider().createKeyedInstanceInPlace(typeid(TService), serviceKey);
-            details::RequireInstance::valid(instance);
-            if constexpr (std::is_move_constructible_v<TService>)
-            {
-                return instance.moveOutAs<TService>();
-            }
-            else
-            {
-                return instance.copyAs<TService>();
-            }
+            return safeAction([&]() -> TService {
+                auto instance = getInstanceProvider().createKeyedInstanceInPlace(typeid(TService), serviceKey);
+                details::RequireInstance::valid(instance);
+                if constexpr (std::is_move_constructible_v<TService>)
+                {
+                    return instance.moveOutAs<TService>();
+                }
+                else
+                {
+                    return instance.copyAs<TService>();
+                }
+            });
         }
 
         /**
@@ -367,10 +392,12 @@ namespace sb::di
          */
         template <class TService> std::vector<std::unique_ptr<TService>> createServices()
         {
-            auto instances = getInstanceProvider().tryCreateInstances(typeid(TService));
-            return instances.map([&](ServiceInstance &instance) {
-                details::RequireInstance::valid(instance);
-                return instance.moveOutAsUniquePtr<TService>();
+            return safeAction([&]() -> std::vector<std::unique_ptr<TService>> {
+                auto instances = getInstanceProvider().tryCreateInstances(typeid(TService));
+                return instances.map([&](ServiceInstance &instance) {
+                    details::RequireInstance::valid(instance);
+                    return instance.moveOutAsUniquePtr<TService>();
+                });
             });
         }
 
@@ -382,21 +409,34 @@ namespace sb::di
          * Example:
          * @code{.cpp}
          * auto provider = ServiceCollection{}
-         *              .addTransient<ITestClass, TestClass1>()
-         *              .addTransient<ITestClass, TestClass2>()
+         *              .addKeyedTransient<ITestClass, TestClass1>("key")
+         *              .addKeyedTransient<ITestClass, TestClass2>("key")
          *              .buildServiceProvider();
          *
-         * std::vector<std::unique_ptr<ITestClass>> services = provider.createServices<ITestClass>();
+         * std::vector<std::unique_ptr<ITestClass>> services = provider.createKeyedServices<ITestClass>("key");
          * @endcode
          */
         template <class TService>
         std::vector<std::unique_ptr<TService>> createKeyedServices(const std::string_view serviceKey)
         {
-            auto instances = getInstanceProvider().tryCreateKeyedInstances(typeid(TService), serviceKey);
-            return instances.map([&](ServiceInstance &instance) {
-                details::RequireInstance::valid(instance);
-                return instance.moveOutAsUniquePtr<TService>();
+            return safeAction([&]() -> std::vector<std::unique_ptr<TService>> {
+                auto instances = getInstanceProvider().tryCreateKeyedInstances(typeid(TService), serviceKey);
+                return instances.map([&](ServiceInstance &instance) {
+                    details::RequireInstance::valid(instance);
+                    return instance.moveOutAsUniquePtr<TService>();
+                });
             });
         }
+
+      private:
+        template <class TAction> auto safeAction(TAction action)
+        {
+            if (_syncMutex)
+            {
+                std::lock_guard lock{*_syncMutex};
+                return action();
+            }
+            return action();
+        }
     };
 } // namespace sb::di
diff --git a/Include/SevenBit/DI/ServiceProviderOptions.hpp b/Include/SevenBit/DI/ServiceProviderOptions.hpp
index c4265d2..8eea451 100644
--- a/Include/SevenBit/DI/ServiceProviderOptions.hpp
+++ b/Include/SevenBit/DI/ServiceProviderOptions.hpp
@@ -33,5 +33,11 @@ namespace sb::di
          * @details If set to true provider will search for service in singleton container first then in scoped
          */
         bool searchInSigletonsFirst = true;
+
+        /**
+         * @brief Enables thread safe mode
+         * @details Provider will synchronize service accesses between threads
+         */
+        bool threadSafe = false;
     };
 } // namespace sb::di
diff --git a/README.md b/README.md
index 54db97f..6aafa3b 100644
--- a/README.md
+++ b/README.md
@@ -17,19 +17,20 @@
   </p>
 
   <h4>
-    <a href="https://7bitDI.readthedocs.io/en/latest/index.html">Documentation & Examples</a>
+    <a href="https://7bitDI.readthedocs.io">Documentation & Examples</a>
   </h4>
 </div>
 
 <br />
 
-## Built With
+## Main Features
 
-- [Google Test](https://github.com/google/googletest)
-- [Google Benchmark](https://github.com/google/benchmark)
-- [Sphinx](https://www.sphinx-doc.org/en/master/)
-- [Breathe](https://breathe.readthedocs.io/en/latest/)
-- [Quom](https://pypi.org/project/quom/)
+- Implementation separation
+- Multiple implementations
+- Keyed services
+- Service aliases
+- Thread safe
+- Strong destruction order
 
 ## Supported Platforms
 
@@ -52,11 +53,15 @@ The library is officially supported on the following platforms:
 If you notice any problems/bugs, please file an issue on the repository GitHub Issue Tracker. Pull requests containing
 fixes are welcome!
 
+## Documentation
+
+https://7bitDI.readthedocs.io
+
 ## Installation
 
 ### There are a few ways of installation:
 
-### 1. Using Cmake fetch content api - Recommended
+### 1. Using Cmake fetch content API - Recommended
 
 Update CMakeLists.txt file with the following code
 
@@ -65,7 +70,7 @@ include(FetchContent)
 FetchContent_Declare(
         7bitDI
         GIT_REPOSITORY https://github.com/7bitcoder/7bitDI.git
-        GIT_TAG v3.2.0
+        GIT_TAG v3.3.0
 )
 FetchContent_MakeAvailable(7bitDI)
 
@@ -78,7 +83,7 @@ Download and install A [Conan](https://conan.io/), and create conanfile.txt in t
 
 ```
 [requires]
-7bitdi/3.2.0
+7bitdi/3.3.0
 ```
 
 change the version to newer if available, then run the command:
@@ -230,6 +235,14 @@ actionA, actionB executed.
 ```
 
 More examples and tutorials are available on the
-[Documentation & Examples](https://7bitDI.readthedocs.io/en/latest/index.html) page
+[Documentation & Examples](https://7bitDI.readthedocs.io) page
+
+## Built With
+
+- [Google Test](https://github.com/google/googletest)
+- [Google Benchmark](https://github.com/google/benchmark)
+- [Sphinx](https://www.sphinx-doc.org/en/master/)
+- [Breathe](https://breathe.readthedocs.io/en/latest/)
+- [Quom](https://pypi.org/project/quom/)
 
 @7bitcoder Sylwester Dawida 2023
diff --git a/Tests/Helpers/Mocks/ServiceInstanceProviderMock.hpp b/Tests/Helpers/Mocks/ServiceInstanceProviderMock.hpp
index dc315cf..4fa46f9 100644
--- a/Tests/Helpers/Mocks/ServiceInstanceProviderMock.hpp
+++ b/Tests/Helpers/Mocks/ServiceInstanceProviderMock.hpp
@@ -7,6 +7,7 @@
 struct ServiceInstanceProviderMock : public sb::di::IServiceInstanceProvider
 {
     MOCK_METHOD((std::unique_ptr<sb::di::IServiceInstanceProvider>), createScope, (), (const override));
+    MOCK_METHOD((std::recursive_mutex *), tryGetSyncMutex, (), (override));
     MOCK_METHOD((void), init, (sb::di::ServiceProvider &), (override));
     MOCK_METHOD((const sb::di::ServiceInstance *), tryGetInstance, (sb::di::TypeId serviceTypeId), (override));
     MOCK_METHOD((const sb::di::ServiceInstance &), getInstance, (sb::di::TypeId serviceTypeId), (override));
diff --git a/Tests/Integration/ThreadSafeTest.cpp b/Tests/Integration/ThreadSafeTest.cpp
new file mode 100644
index 0000000..0211305
--- /dev/null
+++ b/Tests/Integration/ThreadSafeTest.cpp
@@ -0,0 +1,78 @@
+#include <gtest/gtest.h>
+#include <thread>
+
+#include "../Helpers/Classes/Complex.hpp"
+#include <SevenBit/DI/ServiceCollection.hpp>
+
+class ThreadSafeTest : public testing::Test
+{
+  protected:
+    static void SetUpTestSuite() {}
+
+    ThreadSafeTest() {}
+
+    void SetUp() override {}
+
+    void TearDown() override {}
+
+    ~ThreadSafeTest() override = default;
+
+    static void TearDownTestSuite() {}
+};
+
+void getSafeServices(sb::di::ServiceProvider &provider)
+{
+    auto &service1 = provider.getService<ITestComplexClass1>();
+    auto &service2 = provider.getService<ITestComplexClass2>();
+    auto service3 = provider.createService<ITestComplexClass3>();
+    auto &service4 = provider.getService<ITestComplexClass4>();
+    auto &service5 = provider.getService<ITestComplexClass5>();
+    auto &service6 = provider.getService<ITestComplexClass6>();
+
+    EXPECT_EQ(service1.number(), 1);
+    EXPECT_EQ(service2.number(), 2);
+    EXPECT_EQ(service3->number(), 3);
+    EXPECT_EQ(service4.number(), 4);
+    EXPECT_EQ(service5.number(), 5);
+    EXPECT_EQ(service6.number(), 6);
+    EXPECT_EQ(service2.getOne(), &service1);
+    EXPECT_EQ(service3->getOne(), &service1);
+    EXPECT_EQ(service3->getTwo(), &service2);
+    EXPECT_EQ(service4.getOne(), &service1);
+    EXPECT_EQ(service4.getTwo(), &service2);
+    EXPECT_NE(service4.getThree().get(), service3.get());
+    EXPECT_EQ(service5.getOne(), &service1);
+    EXPECT_EQ(service5.getTwo(), &service2);
+    EXPECT_NE(service5.makeThree(), service3);
+    EXPECT_EQ(&service6.getOne(), &service1);
+    EXPECT_EQ(&service6.getTwo(), &service2);
+    EXPECT_FALSE(service6.getNonExisting());
+    EXPECT_NE(service6.makeThree(), service3);
+}
+
+TEST_F(ThreadSafeTest, ShouldGetSafeServices)
+{
+    sb::di::ServiceProviderOptions options;
+    options.threadSafe = true;
+
+    auto provider = sb::di::ServiceCollection{}
+                        .addSingleton<ITestComplexClass1, TestComplexClass1>()
+                        .addSingleton<ITestComplexClass2, TestComplexClass2>()
+                        .addTransient<ITestComplexClass3, TestComplexClass3>()
+                        .addScoped<ITestComplexClass4, TestComplexClass4>()
+                        .addScoped<ITestComplexClass5, TestComplexClass5>()
+                        .addScoped<ITestComplexClass6, TestComplexClass6>()
+                        .buildServiceProvider(options);
+
+    constexpr size_t maxThreads = 50;
+    std::vector<std::thread> threads;
+    threads.reserve(maxThreads);
+    for (size_t i = 0; i < maxThreads; ++i)
+    {
+        threads.emplace_back(getSafeServices, std::ref(provider));
+    }
+    for (auto &th : threads)
+    {
+        th.join();
+    }
+}