diff --git a/.clang-format b/.clang-format
index e7fd784dccff38f5515e53349eb2c918c770770e..778726d25a4e606f9d50d65846e00c649f3649b9 100644
--- a/.clang-format
+++ b/.clang-format
@@ -62,6 +62,7 @@ CommentPragmas: '^ KEEP pragma:'
 ForEachMacros:
   - 'for_each'
   - 'for_ever'
+  - 'forever'
   - 'parallel_for'
   - 'script_class'
   - 'function_class'
diff --git a/PreCompiledHeaders.cmake b/PreCompiledHeaders.cmake
index 1de55147c549a687610fcada06e1d4d5cd19d2be..e0a4d70d639d15cec9971433e9744d44b9a3af31 100644
--- a/PreCompiledHeaders.cmake
+++ b/PreCompiledHeaders.cmake
@@ -36,6 +36,7 @@ set(EXT_INC PRIVATE
 set(QT_STRUCT_INC
     PRIVATE
     <qglobal.h>
+    <QThread>
     <QtGlobal>
     <QObject>
     <QRegularExpression>
diff --git a/src/Lib/Log.cc b/src/Lib/Log.cc
index db13553bebf15eef33479fabcd5d0ba6a47be9e0..245a8df13a5bab15490a249bc809fc041333b0e5 100644
--- a/src/Lib/Log.cc
+++ b/src/Lib/Log.cc
@@ -10,6 +10,28 @@ LogLevel::toStdStringView(const LogLevel::Level lvl) noexcept
 }
 }
 
+// LogSinkUpdater implementations
+namespace Vivy
+{
+StlLogSinkUpdater::StlLogSinkUpdater(MutexType *const lock, MessageQueueType *const queue) noexcept
+    : updater(lock, queue)
+{
+    setPriority(QThread::LowestPriority);
+}
+
+void
+StlLogSinkUpdater::run() noexcept
+{
+    forever {
+        if (QThread::currentThread()->isInterruptionRequested())
+            return;
+        if (updater.isMessageAvailable())
+            emit messageAvailable();
+        usleep(chrono::microseconds(10000).count()); // Sleeps for 0.1s
+    }
+}
+}
+
 // Vivy::LogSinkDispatcher and child classes implementation
 namespace Vivy
 {
@@ -54,8 +76,24 @@ StderrLogSinkDispatcher::handleLogMessage(const std::string_view category,
 // Vivy::LogSink implementation
 namespace Vivy
 {
+LogSink::LogSink() noexcept
+{
+    workerThread = new StlLogSinkUpdater(&messageQueueLock, &messageQueue);
+    connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater);
+    connect(
+        workerThread, &StlLogSinkUpdater::messageAvailable, this, [this]() { flush(); },
+        Qt::QueuedConnection);
+
+    workerThread->start();
+}
+
 // Flush all messages before exiting
-LogSink::~LogSink() noexcept { flush(); }
+LogSink::~LogSink() noexcept
+{
+    workerThread->requestInterruption();
+    workerThread->wait();
+    flush();
+}
 
 // Get the log message from the logger and add it to the sink's queue.
 void
diff --git a/src/Lib/Log.hh b/src/Lib/Log.hh
index 31b0ebc837e536c4c6f6f9c7489dbcad4882ae8b..0cfcc0d580f299d07bcf19a4c358a62ac3144ef3 100644
--- a/src/Lib/Log.hh
+++ b/src/Lib/Log.hh
@@ -51,15 +51,6 @@
 
 #define VIVY_LOG_QUOTED(something) '\'' << (something) << '\''
 
-// Install logger, use the global LogSink
-#define VIVY_APP_LOGGABLE_OBJECT(name, logger) \
-    VIVY_LOGGABLE_OBJECT(vivyApp->getLogSink(), name, logger)
-
-// Install logger, use the global LogSink, with a stored name like in the
-// VIVY_LOGGABLE_OBJECT_BY_STORED_NAME macro.
-#define VIVY_APP_LOGGABLE_OBJECT_BY_STORED_NAME(name, logger) \
-    VIVY_LOGGABLE_OBJECT_BY_STORED_NAME(vivyApp->getLogSink(), name, logger)
-
 namespace Vivy
 {
 class LogSinkDispatcher;
@@ -70,6 +61,7 @@ class LogMessage;
 // The severity of an event. Critical will cause the LogSink to flush all
 // messages to its emeters and then abort.
 struct LogLevel final {
+    // NOTE: The order matters:
     enum Level : int {
         None, // In option setup to disable logs
         Debug,
@@ -84,6 +76,8 @@ struct LogLevel final {
 
 private:
     using Array = std::array<const std::string_view, ___MaxAndUnused>;
+
+    // WARN: The order matters!
     static inline constexpr Array LevelsStringViews = { "None",   "Debug", "Info",
                                                         "Warnin", "Error", "Critical" };
 
@@ -122,17 +116,63 @@ public:
     void handleLogMessage(const std::string_view, const LogMessage &) noexcept override;
 };
 
+// Class used to check the messageQueue and send needFlush or something like
+// that messages. It needs to be moved to its own thread and connected with the
+// queue version of the QObject::connect method.
+template <class MutexType, class MessageQueueType> class LogSinkUpdater final {
+    MutexType *const messageQueueLock;
+    MessageQueueType *const messageQueue;
+
+    using size_type = typename MessageQueueType::size_type;
+
+public:
+    explicit LogSinkUpdater(MutexType *const lock, MessageQueueType *const queue) noexcept
+        : messageQueueLock(lock)
+        , messageQueue(queue)
+    {
+    }
+
+    bool isMessageAvailable() const noexcept
+    {
+        std::lock_guard<MutexType> lockGuard(*messageQueueLock);
+        size_type size = messageQueue->size();
+        return size != 0;
+    }
+};
+
+// LogSinkUpdater controller, needed because templated Q_OBJECT are not
+// supported by Qt. This controller is specialized for a std implementation of
+// the message queue.
+class StlLogSinkUpdater final : public QThread {
+    Q_OBJECT
+
+public:
+    using MutexType        = std::mutex;
+    using MessageQueueType = std::vector<std::tuple<const std::string_view, LogMessage>>;
+
+    explicit StlLogSinkUpdater(MutexType *const, MessageQueueType *const) noexcept;
+
+    void run() noexcept override;
+
+private:
+    LogSinkUpdater<MutexType, MessageQueueType> updater;
+
+signals:
+    void messageAvailable();
+};
+
 // LogSink is the parent logger. It will recieve messages and display them to a
 // console or to std::cerr or to a file, etc. The save to over file, etc will
 // be donne by the LogSinkDispatcher.
-class LogSink {
+class LogSink : QObject {
+    Q_OBJECT
     VIVY_UNMOVABLE_OBJECT(LogSink)
 
-    explicit LogSink() noexcept = default;
+    explicit LogSink() noexcept;
 
 public:
     static std::shared_ptr<LogSink> newSink() noexcept;
-    ~LogSink() noexcept;
+    ~LogSink() noexcept override;
 
     void registerLogDispatcher(std::shared_ptr<LogSinkDispatcher>) noexcept;
     void registerLogger(std::shared_ptr<Logger>) noexcept;
@@ -156,6 +196,7 @@ public:
     }
 
 private:
+    StlLogSinkUpdater *workerThread;
     std::mutex messageQueueLock{};
     std::vector<std::tuple<const std::string_view, LogMessage>> messageQueue;
     std::vector<std::shared_ptr<LogSinkDispatcher>> logDispatchers;
diff --git a/src/UI/FakeVim/FakeVimHandler.cc b/src/UI/FakeVim/FakeVimHandler.cc
index 3d455d8b3b63e5900169c59ab00a53fd737fdb12..c1f327d91972dbdfef6e502aa1df706378c5089d 100644
--- a/src/UI/FakeVim/FakeVimHandler.cc
+++ b/src/UI/FakeVim/FakeVimHandler.cc
@@ -6156,8 +6156,7 @@ FakeVimHandler::Private::handleExMapCommand(const ExCommand &cmd0) // :map
     QString args = cmd0.args;
     bool silent  = false;
     bool unique  = false;
-    forever
-    {
+    forever {
         if (eatString("<silent>", &args)) {
             silent = true;
         } else if (eatString("<unique>", &args)) {
diff --git a/src/VivyApplication.hh b/src/VivyApplication.hh
index 543ce040d094965db4fc60185bc4ac60f2dae540..18b9cacec08da43437758cdca2e0662551ac4a52 100644
--- a/src/VivyApplication.hh
+++ b/src/VivyApplication.hh
@@ -4,8 +4,18 @@
 #error "This is a C++ header"
 #endif
 
+// Get the VivyApplication pointer
 #define vivyApp (static_cast<::Vivy::VivyApplication *>(VivyApplication::instance()))
 
+// Install logger, use the global LogSink
+#define VIVY_APP_LOGGABLE_OBJECT(name, logger) \
+    VIVY_LOGGABLE_OBJECT(vivyApp->getLogSink(), name, logger)
+
+// Install logger, use the global LogSink, with a stored name like in the
+// VIVY_LOGGABLE_OBJECT_BY_STORED_NAME macro.
+#define VIVY_APP_LOGGABLE_OBJECT_BY_STORED_NAME(name, logger) \
+    VIVY_LOGGABLE_OBJECT_BY_STORED_NAME(vivyApp->getLogSink(), name, logger)
+
 #define currentVivyDocument() dynamic_cast<::Vivy::VivyDocument *>(vivyApp->getCurrentDocument())
 #define currentScriptDocument dynamic_cast<::Vivy::ScriptDocument *>(vivyApp->getCurrentDocument())