diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,8 @@
+## 3.2.8
+
+* Take another road under the Windows native I/O manager
+  [#222](https://github.com/kazu-yamamoto/logger/pull/222)
+
 ## 3.2.7
 
 * Don't eat up an asynchronous exception.
diff --git a/System/Log/FastLogger.hs b/System/Log/FastLogger.hs
--- a/System/Log/FastLogger.hs
+++ b/System/Log/FastLogger.hs
@@ -108,6 +108,15 @@
         --   'BufSize' is a buffer size
         --   for each capability.
         --   File rotation is done on-demand.
+        --
+        --   On Windows this needs the native I\/O manager
+        --   (@+RTS --io-manager=native@).  Rotation renames the
+        --   log file while it is still open, which the
+        --   descriptor the POSIX subsystem opens there is not
+        --   shared for; the rename is refused and the file
+        --   stops rotating.  Nothing is lost -- the log keeps
+        --   being written to the one file, past the size asked
+        --   for.
     LogFileTimedRotate
         :: TimedFileLogSpec
         -> BufSize
diff --git a/System/Log/FastLogger/File.hs b/System/Log/FastLogger/File.hs
--- a/System/Log/FastLogger/File.hs
+++ b/System/Log/FastLogger/File.hs
@@ -76,6 +76,14 @@
     dir = takeDirectory file
 
 -- | Rotating log files.
+--
+-- The log file is renamed while it is still open, which every platform
+-- allows except Windows, and Windows allows it only of a file opened
+-- sharing deletion.  The descriptor 'GHC.IO.FD' opens is not, so under the
+-- POSIX subsystem there -- @+RTS --io-manager=posix@, which is still the
+-- default -- this is refused and the file does not rotate.  Under the
+-- native one the file is a 'System.IO.Handle', which is shared for
+-- deletion, and it does.
 rotate :: FileLogSpec -> IO ()
 rotate spec = mapM_ move srcdsts
   where
diff --git a/System/Log/FastLogger/FileIO.hs b/System/Log/FastLogger/FileIO.hs
--- a/System/Log/FastLogger/FileIO.hs
+++ b/System/Log/FastLogger/FileIO.hs
@@ -1,5 +1,25 @@
-module System.Log.FastLogger.FileIO where
+{-# LANGUAGE CPP #-}
 
+-- | Where the bytes actually go.
+--
+-- The rest of fast-logger fills its own buffer and hands it here as a raw
+-- pointer, so this is deliberately one layer below 'Handle': the point of
+-- 'writeRawBufferPtr2FD' is that nothing buffers the bytes a second time.
+--
+-- Windows has two I\/O subsystems and chooses between them at run time, from
+-- the @--io-manager=@ RTS flag, so on Windows an 'FD' is one of two things.
+-- See the note on 'openFileFD'.
+module System.Log.FastLogger.FileIO (
+    FD,
+    closeFD,
+    openFileFD,
+    getStderrFD,
+    getStdoutFD,
+    writeRawBufferPtr2FD,
+    invalidFD,
+    isFDValid,
+) where
+
 import Foreign.Ptr (Ptr)
 import GHC.IO.Device (close)
 import GHC.IO.FD (openFile, stderr, stdout, writeRawBufferPtr)
@@ -8,6 +28,90 @@
 
 import System.Log.FastLogger.Imports
 
+#if defined(mingw32_HOST_OS)
+import GHC.IO.SubSystem (isWindowsNativeIO)
+import qualified System.IO as SIO
+#endif
+
+#if defined(mingw32_HOST_OS)
+
+-- | A file descriptor, or on Windows under the native I\/O manager a
+--   'SIO.Handle' standing in for one.
+data FD
+    = PosixFD !POSIX.FD
+    | -- | Under the native I\/O manager.  The 'SIO.Handle' is left with
+      -- whatever buffering it came with and flushed after every write, so
+      -- the bytes are no more buffered than they were before.
+      NativeFD !SIO.Handle
+    | InvalidFD
+
+-- | Opening a log file for appending.
+--
+-- Under the POSIX subsystem this is a file descriptor, as it always was.
+--
+-- Under the native subsystem it cannot be.  There a 'POSIX.FD' is a C
+-- runtime descriptor, and the I\/O manager works in terms of Windows
+-- handles registered with a completion port; the two cannot be mixed, and
+-- @base@ says so by replacing every method of @IODevice FD@ and @RawIO FD@
+-- with an @error@ when that subsystem is in force.  Opening and the raw
+-- write happen to be plain functions and so still work, which is the trap:
+-- a log file could be written and never closed, and it stayed locked for
+-- the life of the process.
+--
+-- 'SIO.openFile' gives a handle the running subsystem owns, whichever it
+-- is.  Appending is its business too, which matters because the native
+-- subsystem writes at an offset given per call and has no @O_APPEND@ of
+-- its own.
+openFileFD :: FilePath -> IO FD
+openFileFD f
+    | isWindowsNativeIO = NativeFD <$> SIO.openFile f SIO.AppendMode
+    | otherwise = PosixFD . fst <$> openFile f AppendMode False
+
+-- | The standard streams are handed to us, not opened by us, and under the
+--   native subsystem the descriptor numbered 1 is not what the process is
+--   actually writing through: bytes put there were accepted and never
+--   appeared.
+getStdoutFD :: IO FD
+getStdoutFD
+    | isWindowsNativeIO = return $ NativeFD SIO.stdout
+    | otherwise = return $ PosixFD stdout
+
+getStderrFD :: IO FD
+getStderrFD
+    | isWindowsNativeIO = return $ NativeFD SIO.stderr
+    | otherwise = return $ PosixFD stderr
+
+-- | Only ever called for a log file, never for a standard stream.
+closeFD :: FD -> IO ()
+closeFD (PosixFD fd) = close fd
+closeFD (NativeFD h) = SIO.hClose h
+closeFD InvalidFD = return ()
+
+writeRawBufferPtr2FD :: IORef FD -> Ptr Word8 -> Int -> IO Int
+writeRawBufferPtr2FD fdref bf len = do
+    fd <- readIORef fdref
+    case fd of
+        PosixFD fd'
+            | POSIX.fdFD fd' /= -1 ->
+                fromIntegral <$> writeRawBufferPtr "write" fd' bf 0 (fromIntegral len)
+        -- 'SIO.hPutBuf' writes all of it or raises; there is no short write
+        -- to report back.
+        NativeFD h -> do
+            SIO.hPutBuf h bf len
+            SIO.hFlush h
+            return len
+        _ -> return (-1)
+
+invalidFD :: FD
+invalidFD = InvalidFD
+
+isFDValid :: FD -> Bool
+isFDValid (PosixFD fd) = POSIX.fdFD fd /= -1
+isFDValid (NativeFD _) = True
+isFDValid InvalidFD = False
+
+#else
+
 type FD = POSIX.FD
 
 closeFD :: FD -> IO ()
@@ -36,3 +140,5 @@
 
 isFDValid :: POSIX.FD -> Bool
 isFDValid fd = POSIX.fdFD fd /= -1
+
+#endif
diff --git a/fast-logger.cabal b/fast-logger.cabal
--- a/fast-logger.cabal
+++ b/fast-logger.cabal
@@ -1,6 +1,6 @@
 cabal-version:      >=1.10
 name:               fast-logger
-version:            3.2.7
+version:            3.2.8
 license:            BSD3
 license-file:       LICENSE
 maintainer:         Kazu Yamamoto <kazu@iij.ad.jp>
