diff --git a/Data/ByteString/FastBuilder.hs b/Data/ByteString/FastBuilder.hs
--- a/Data/ByteString/FastBuilder.hs
+++ b/Data/ByteString/FastBuilder.hs
@@ -74,6 +74,7 @@
   , toLazyByteStringWith
   , toStrictByteString
   , hPutBuilder
+  , hPutBuilderLen
   , hPutBuilderWith
 
   -- * Performance tuning
diff --git a/Data/ByteString/FastBuilder/Internal.hs b/Data/ByteString/FastBuilder/Internal.hs
--- a/Data/ByteString/FastBuilder/Internal.hs
+++ b/Data/ByteString/FastBuilder/Internal.hs
@@ -36,6 +36,7 @@
   , toLazyByteStringWith
   , toStrictByteString
   , hPutBuilder
+  , hPutBuilderLen
   , hPutBuilderWith
 
   -- * Basic builders
@@ -152,8 +153,14 @@
       -- size limit is reached. After that, the destination switches
       -- to a 'ThreadedSink'.
 
--- | A mutable buffer. The 'Int' specifies where the data start.
-data Queue = Queue !(ForeignPtr Word8) !Int{-start-}
+-- | A mutable buffer.
+data Queue = Queue
+  { queueBuffer :: !(ForeignPtr Word8)
+  , queueStart :: !Int
+    -- ^ Starting position.
+  , queueTotal :: !Int
+    -- ^ Bytes written to the handle so far.
+  }
   -- TODO: this is not really needed
 
 -- | A request from the driver thread to the builder thread.
@@ -462,19 +469,30 @@
 
 -- | Output a 'Builder' to a 'IO.Handle'.
 hPutBuilder :: IO.Handle -> Builder -> IO ()
-hPutBuilder !h builder = hPutBuilderWith h 100 4096 builder
+hPutBuilder !h builder = void $ hPutBuilderLen h builder
+{-# INLINE hPutBuilder #-}
 
+-- | Output a 'Builder' to a 'IO.Handle'. Returns the number of bytes written.
+hPutBuilderLen :: IO.Handle -> Builder -> IO Int
+hPutBuilderLen !h builder = hPutBuilderWith h 100 4096 builder
+
 -- | Like 'hPutBuffer', but allows the user to specify the initial
 -- and the subsequent desired buffer sizes. This function may be useful for
 -- setting large buffer when high throughput I/O is needed.
-hPutBuilderWith :: IO.Handle -> Int -> Int -> Builder -> IO ()
+hPutBuilderWith :: IO.Handle -> Int -> Int -> Builder -> IO Int
 hPutBuilderWith !h !initialCap !nextCap builder = do
   fptr <- mallocForeignPtrBytes initialCap
-  qRef <- newIORef $ Queue fptr 0
+  qRef <- newIORef $ Queue
+    { queueBuffer = fptr
+    , queueStart =  0
+    , queueTotal = 0
+    }
   let !base = unsafeForeignPtrToPtr fptr
   cur <- runBuilder builder (HandleSink h nextCap qRef)
     base (base `plusPtr` initialCap)
   flushQueue h qRef cur
+  Queue{ queueTotal = len } <- readIORef qRef
+  return len
 
 ----------------------------------------------------------------
 -- builders
@@ -647,7 +665,7 @@
     HandleSink h nextCap queueRef -> do
       cur <- getCur
       io $ flushQueue h queueRef cur
-      switchQueue queueRef $ max nextCap (I# n)
+      switchQueue queueRef (max nextCap (I# n))
 {-# NOINLINE getBytes_ #-}
 
 -- | Return the remaining size of the current buffer, in bytes.
@@ -715,26 +733,35 @@
 -- the 'Queue'.
 flushQueue :: IO.Handle -> IORef Queue -> Ptr Word8 -> IO ()
 flushQueue !h !qRef !cur = do
-  Queue fptr start <- readIORef qRef
+  Queue{ queueBuffer = fptr, queueStart = start, queueTotal = total }
+    <- readIORef qRef
   let !end = cur `minusPtr` unsafeForeignPtrToPtr fptr
   when (end > start) $ do
     S.hPut h $ S.fromForeignPtr fptr start (end - start)
-    writeIORef qRef $ Queue fptr end
+    writeIORef qRef Queue
+      { queueBuffer = fptr
+      , queueStart = end
+      , queueTotal = total + end - start
+      }
 
--- | @switchQueue qRef minSize@ discards the old 'Queue' and sets up
+-- | @switchQueue qRef minSize adv@ discards the old 'Queue' and sets up
 -- a new empty 'Queue' of at least @minSize@ large. If the old 'Queue'
 -- is large enough, it is re-used.
 switchQueue :: IORef Queue -> Int -> BuildM ()
 switchQueue !qRef !minSize = do
   end <- getCur
-  Queue fptr _ <- io $ readIORef qRef
+  Queue{ queueBuffer = fptr, queueTotal = total } <- io $ readIORef qRef
   let !base = unsafeForeignPtrToPtr fptr
   let !cap = end `minusPtr` base
   newFptr <- if minSize <= cap
     then return fptr
     else io $ mallocForeignPtrBytes minSize
   let !newBase = unsafeForeignPtrToPtr newFptr
-  io $ writeIORef qRef $ Queue newFptr 0
+  io $ writeIORef qRef Queue
+    { queueBuffer = newFptr
+    , queueStart = 0
+    , queueTotal = total
+    }
   setCur newBase
   setEnd $ newBase `plusPtr` max minSize cap
 
diff --git a/fast-builder.cabal b/fast-builder.cabal
--- a/fast-builder.cabal
+++ b/fast-builder.cabal
@@ -1,5 +1,5 @@
 name:                fast-builder
-version:             0.1.0.2
+version:             0.1.1.0
 synopsis:            Fast ByteString Builder
 description:         An efficient implementation of ByteString builder. It should be faster than
                      the standard implementation in most cases.
diff --git a/tests/prop.hs b/tests/prop.hs
--- a/tests/prop.hs
+++ b/tests/prop.hs
@@ -196,6 +196,14 @@
 prop_writeWrite w0 w1
   = toStrictByteString (word8 w0 <> word8 w1) == BS.pack [w0, w1]
 
+-- | hPutBuilderLen returns the correct number of bytes.
+prop_length :: BuilderTree -> QC.Property
+prop_length tree = QC.ioProperty $ IO.withFile "/dev/null" IO.WriteMode $ \h -> do
+  let b = mkBuilder tree
+  let len = BS.length $ toStrictByteString b
+  len' <- hPutBuilderLen h b
+  return $ len QC.=== len'
+
 return []
 
 main :: IO ()
