diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,3 +1,10 @@
+# 1.1.1
+
+- `withBatchedHandler` no longer prints empty log messages. Previously,
+  if you ran a program that didn't log but used `withBatchedHandler` (or anything
+  that used that), an empty log message would be output. Thanks to @codedmart
+  for fixing this.
+
 # 1.1.0
 
 *Breaking changes*:
diff --git a/logging-effect.cabal b/logging-effect.cabal
--- a/logging-effect.cabal
+++ b/logging-effect.cabal
@@ -1,5 +1,5 @@
 name: logging-effect
-version: 1.1.0
+version: 1.1.1
 synopsis: A mtl-style monad transformer for general purpose & compositional logging
 homepage: https://github.com/ocharles/logging-effect
 license: BSD3
@@ -26,6 +26,7 @@
                      , wl-pprint-text >= 1.1.0.4 && < 1.2
                      , monad-control >= 1.0.0.4 && < 1.1
                      , transformers-base >= 0.4.4 && < 0.5
+                     , semigroups >= 0.16.2.2 && < 0.19
   hs-source-dirs:      src
   default-language:    Haskell2010
   ghc-options: -O2 -Wall
diff --git a/src/Control/Monad/Log.hs b/src/Control/Monad/Log.hs
--- a/src/Control/Monad/Log.hs
+++ b/src/Control/Monad/Log.hs
@@ -103,6 +103,7 @@
 import System.IO (Handle)
 import qualified Data.Text.Lazy as LT
 import qualified Text.PrettyPrint.Leijen.Text as PP
+import qualified Data.List.NonEmpty as NEL
 
 -- For 'MonadLog' pass-through instances.
 import qualified Control.Monad.Trans.Identity as Identity
@@ -463,21 +464,21 @@
 -- 'BatchingOptions'.
 withBatchedHandler :: (MonadIO io,MonadMask io)
                    => BatchingOptions
-                   -> ([message] -> IO ())
+                   -> (NEL.NonEmpty message -> IO ())
                    -> (Handler io message -> io a)
                    -> io a
 withBatchedHandler BatchingOptions{..} flush k =
-  do do closed <- liftIO (newTVarIO False)
-        channel <- liftIO (newTBQueueIO flushMaxQueueSize)
-        bracket (liftIO (async (repeatWhileTrue (publish closed channel))))
-                (\publisher ->
-                   do liftIO (do atomically (writeTVar closed True)
-                                 wait publisher))
-                (\_ ->
-                   k (\msg ->
-                        liftIO (atomically
-                                  (writeTBQueue channel msg <|>
-                                   check (not blockWhenFull)))))
+  do closed <- liftIO (newTVarIO False)
+     channel <- liftIO (newTBQueueIO flushMaxQueueSize)
+     bracket (liftIO (async (repeatWhileTrue (publish closed channel))))
+             (\publisher ->
+                do liftIO (do atomically (writeTVar closed True)
+                              wait publisher))
+             (\_ ->
+                k (\msg ->
+                     liftIO (atomically
+                               (writeTBQueue channel msg <|>
+                                check (not blockWhenFull)))))
   where repeatWhileTrue m =
           do again <- m
              if again
@@ -491,7 +492,7 @@
                        flushAfter flushAlarm <|> flushFull <|> flushOnClose
                      stillOpen <- fmap not (readTVar closed)
                      return (messages,stillOpen))
-             flush messages
+             mapM_ flush (NEL.nonEmpty messages)
              pure stillOpen
           where flushAfter flushAlarm =
                   do waitDelay flushAlarm
@@ -528,7 +529,7 @@
   -> io a
 withFDHandler options fd ribbonFrac width =
   withBatchedHandler options
-                     (PP.displayIO fd . PP.renderPretty ribbonFrac width . (<> PP.linebreak) . PP.vsep)
+                     (PP.displayIO fd . PP.renderPretty ribbonFrac width . (<> PP.linebreak) . PP.vsep . NEL.toList)
 
 --------------------------------------------------------------------------------
 -- | A 'MonadLog' handler optimised for pure usage. Log messages are accumulated
