diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,10 @@
 # Revision history for Z-Data
 
+## 0.8.1.0  -- 2021-04-23
+
+* Change `ParseChunks` and `parseChunks` to based on `parseChunk`.
+* Remove `parseValueChunks`, add `decodeChunk` to `Z.Data.JSON`.
+
 ## 0.8.0.0  -- 2021-04-20
 
 * Change `Bytes` 's `Hashable` instance to use FNV-1a (proposed by @zypeh).
diff --git a/Z-Data.cabal b/Z-Data.cabal
--- a/Z-Data.cabal
+++ b/Z-Data.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               Z-Data
-version:            0.8.0.0
+version:            0.8.1.0
 synopsis:           Array, vector and text
 description:        This package provides array, slice and text operations
 license:            BSD-3-Clause
diff --git a/Z/Data/JSON.hs b/Z/Data/JSON.hs
--- a/Z/Data/JSON.hs
+++ b/Z/Data/JSON.hs
@@ -32,11 +32,11 @@
     -- * Encode & Decode
   , DecodeError
   , decode, decode', decodeText, decodeText'
-  , ParseChunks, decodeChunks
+  , ParseChunks, decodeChunk, decodeChunks
   , encode, encodeChunks, encodeText
   , prettyJSON, prettyValue
     -- * parse into JSON Value
-  , parseValue, parseValue', parseValueChunks
+  , parseValue, parseValue'
   -- * Generic functions
   , gToValue, gFromValue, gEncodeJSON
   -- * Convert 'Value' to Haskell data
diff --git a/Z/Data/JSON/Base.hs b/Z/Data/JSON/Base.hs
--- a/Z/Data/JSON/Base.hs
+++ b/Z/Data/JSON/Base.hs
@@ -18,11 +18,11 @@
   , -- * Encode & Decode
     DecodeError
   , decode, decode', decodeText, decodeText'
-  , P.ParseChunks, decodeChunks
+  , P.ParseChunks, decodeChunk, decodeChunks
   , encode, encodeChunks, encodeText
   , prettyJSON, JB.prettyValue
     -- * parse into JSON Value
-  , JV.parseValue, JV.parseValue', JV.parseValueChunks
+  , JV.parseValue, JV.parseValue'
   -- * Generic functions
   , gToValue, gFromValue, gEncodeJSON
   -- * Convert 'Value' to Haskell data
@@ -146,17 +146,24 @@
         Left cErr -> (bs', Left (Right cErr))
         Right r   -> (bs', Right r)
 
+-- | Decode a JSON doc chunk.
+decodeChunk :: JSON a => V.Bytes -> P.Result DecodeError a
+{-# INLINE decodeChunk #-}
+decodeChunk bs = loop (P.parseChunk JV.value bs)
+  where
+    loop r = do
+        case r of
+            P.Success v rest ->
+                case convertValue v of
+                    Left cErr -> P.Failure (Right cErr) rest
+                    Right r'  -> P.Success r' rest
+            P.Failure e rest -> P.Failure (Left e) rest
+            P.Partial f' -> P.Partial (loop . f')
+
 -- | Decode JSON doc chunks, return trailing bytes.
-decodeChunks :: (JSON a, Monad m) => P.ParseChunks m V.Bytes DecodeError a
+decodeChunks :: (JSON a, Monad m) => P.ParseChunks m DecodeError a
 {-# INLINE decodeChunks #-}
-decodeChunks mb bs = do
-    mr <- P.parseChunks JV.value mb bs
-    case mr of
-        (bs', Left pErr) -> pure (bs', Left (Left pErr))
-        (bs', Right v) ->
-            case convertValue v of
-                Left cErr -> pure (bs', Left (Right cErr))
-                Right r   -> pure (bs', Right r)
+decodeChunks = P.parseChunks decodeChunk
 
 -- | Directly encode data to JSON bytes.
 encode :: JSON a => a -> V.Bytes
diff --git a/Z/Data/JSON/Value.hs b/Z/Data/JSON/Value.hs
--- a/Z/Data/JSON/Value.hs
+++ b/Z/Data/JSON/Value.hs
@@ -27,7 +27,6 @@
     -- * parse into JSON Value
   , parseValue
   , parseValue'
-  , parseValueChunks
     -- * Value Parsers
   , value
   , object
@@ -149,11 +148,6 @@
 parseValue' :: V.Bytes -> Either P.ParseError Value
 {-# INLINE parseValue' #-}
 parseValue' = P.parse' (value <* skipSpaces <* P.endOfInput)
-
--- | Increamental parse 'Value' without consuming trailing bytes.
-parseValueChunks :: Monad m => P.ParseChunks m V.Bytes P.ParseError Value
-{-# INLINE parseValueChunks #-}
-parseValueChunks = P.parseChunks value
 
 --------------------------------------------------------------------------------
 
diff --git a/Z/Data/Parser/Base.hs b/Z/Data/Parser/Base.hs
--- a/Z/Data/Parser/Base.hs
+++ b/Z/Data/Parser/Base.hs
@@ -64,23 +64,23 @@
 --
 -- * Partial: that need for more input data, supply empty bytes to indicate 'endOfInput'
 --
-data Result a
-    = Success a          !V.Bytes
-    | Failure ParseError !V.Bytes
-    | Partial (ParseStep a)
+data Result e r
+    = Success r !V.Bytes
+    | Failure e !V.Bytes
+    | Partial (ParseStep e r)
 
 -- | A parse step consumes 'V.Bytes' and produce 'Result'.
-type ParseStep r = V.Bytes -> Result r
+type ParseStep e r = V.Bytes -> Result e r
 
 -- | Type alias for error message
 type ParseError = [T.Text]
 
-instance Functor Result where
+instance Functor (Result e) where
     fmap f (Success a s)   = Success (f a) s
     fmap f (Partial k)     = Partial (fmap f . k)
     fmap _ (Failure e v)   = Failure e v
 
-instance Show a => Show (Result a) where
+instance (Show e, Show a) => Show (Result e a) where
     show (Success a _)    = "Success " ++ show a
     show (Partial _)      = "Partial _"
     show (Failure errs _) = "Failure: " ++ show errs
@@ -100,9 +100,9 @@
 --        ... k s ... (if we get something useful for next parser)
 --  @
 newtype Parser a = Parser {
-        runParser :: forall r . (ParseError -> ParseStep r)
-                  -> (State# ParserState -> a -> ParseStep r)
-                  -> State# ParserState -> ParseStep r
+        runParser :: forall r . (ParseError -> ParseStep ParseError r)
+                  -> (State# ParserState -> a -> ParseStep ParseError r)
+                  -> State# ParserState -> ParseStep ParseError r
     }
 
 -- | State token tag used in `Parser`
@@ -195,38 +195,32 @@
     unsafeCoerce# (p Failure (\ _ r -> Success r) (unsafeCoerce# s) inp)))
 
 -- | Parse an input chunk
-parseChunk :: Parser a -> V.Bytes -> Result a
+parseChunk :: Parser a -> V.Bytes -> Result ParseError a
 {-# INLINE parseChunk #-}
 parseChunk (Parser p) = runRW# (\ s ->
     unsafeCoerce# (p Failure (\ _ r -> Success r) (unsafeCoerce# s)))
 
 -- | Finish parsing and fetch result, feed empty bytes if it's 'Partial' result.
-finishParsing :: Result a -> (V.Bytes, Either ParseError a)
+finishParsing :: Result ParseError a -> (V.Bytes, Either ParseError a)
 {-# INLINABLE finishParsing #-}
 finishParsing r = case r of
     Success a rest    -> (rest, Right a)
     Failure errs rest -> (rest, Left errs)
     Partial f         -> finishParsing (f V.empty)
 
--- | Type alias for a streaming parser, draw chunk from Monad m (with a initial chunk), return result in @Either err x@.
-type ParseChunks m chunk err x = m chunk -> chunk -> m (chunk, Either err x)
+-- | Type alias for a streaming parser, draw chunk from Monad m with a initial chunk,
+-- return result in @Either err x@.
+type ParseChunks m err x = m V.Bytes -> V.Bytes -> m (V.Bytes, Either err x)
 
--- | Run a parser with an initial input string, and a monadic action
+-- | Run a chunk parser with an initial input string, and a monadic action
 -- that can supply more input if needed.
 --
--- Note, once the monadic action return empty bytes, parsers will stop drawing
--- more bytes (take it as 'endOfInput').
-parseChunks :: Monad m => Parser a -> ParseChunks m V.Bytes ParseError a
+parseChunks :: Monad m => (V.Bytes -> Result e a) -> ParseChunks m e a
 {-# INLINABLE parseChunks #-}
-parseChunks (Parser p) m0 inp = go m0 (runRW# (\ s ->
-    unsafeCoerce# (p Failure (\ _ r -> Success r) (unsafeCoerce# s) inp)))
+parseChunks pc m0 inp = go m0 (pc inp)
   where
     go m r = case r of
-        Partial f -> do
-            inp' <- m
-            if V.null inp'
-            then go (pure V.empty) (f V.empty)
-            else go m (f inp')
+        Partial f -> go m . f =<< m
         Success a rest    -> pure (rest, Right a)
         Failure errs rest -> pure (rest, Left errs)
 
@@ -239,7 +233,7 @@
 -- Once it's finished, return the final result (always 'Success' or 'Failure') and
 -- all consumed chunks.
 --
-runAndKeepTrack :: Parser a -> Parser (Result a, [V.Bytes])
+runAndKeepTrack :: Parser a -> Parser (Result ParseError a, [V.Bytes])
 {-# INLINE runAndKeepTrack #-}
 runAndKeepTrack (Parser pa) = Parser $ \ _ k0 st0 inp ->
     let go !acc r k (st :: State# ParserState) = case r of
@@ -277,9 +271,9 @@
     else Partial (ensureNPartial l inp kf k s)
   where
     {-# INLINABLE ensureNPartial #-}
-    ensureNPartial :: forall r. Int -> V.PrimVector Word8 -> (ParseError -> ParseStep r)
-                   -> (State# ParserState -> () -> ParseStep r)
-                   -> State# ParserState -> ParseStep r
+    ensureNPartial :: forall r. Int -> V.PrimVector Word8 -> (ParseError -> ParseStep ParseError r)
+                   -> (State# ParserState -> () -> ParseStep ParseError r)
+                   -> State# ParserState -> ParseStep ParseError r
     ensureNPartial l0 inp0 kf k s0 =
         let go acc !l s = \ inp -> do
                 let l' = V.length inp
@@ -432,8 +426,8 @@
   where
     -- we want to inline consume if possible
     {-# INLINABLE scanChunksPartial #-}
-    scanChunksPartial :: forall r. s -> (State# ParserState -> (V.PrimVector Word8, s) -> ParseStep r)
-                      -> State# ParserState -> V.PrimVector Word8 -> ParseStep r
+    scanChunksPartial :: forall r. s -> (State# ParserState -> (V.PrimVector Word8, s) -> ParseStep ParseError r)
+                      -> State# ParserState -> V.PrimVector Word8 -> ParseStep ParseError r
     scanChunksPartial s0' k st0 inp0 =
         let go s acc st = \ inp ->
                 if V.null inp
@@ -621,8 +615,9 @@
             then k s () $! V.unsafeDrop n' inp
             else Partial (skipPartial (n'-l) kf k s))
 
-skipPartial :: Int -> (ParseError -> ParseStep r) -> (State# ParserState -> () -> ParseStep r)
-            -> State# ParserState -> ParseStep r
+skipPartial :: Int -> (ParseError -> ParseStep ParseError r)
+            -> (State# ParserState -> () -> ParseStep ParseError r)
+            -> State# ParserState -> ParseStep ParseError r
 {-# INLINABLE skipPartial #-}
 skipPartial n kf k s0 =
     let go !n' s = \ inp ->
@@ -660,7 +655,8 @@
   where
     -- we want to inline p if possible
     {-# INLINABLE skipWhilePartial #-}
-    skipWhilePartial :: forall r. (State# ParserState -> () -> ParseStep r) -> State# ParserState -> ParseStep r
+    skipWhilePartial :: forall r. (State# ParserState -> () -> ParseStep ParseError r)
+                     -> State# ParserState -> ParseStep ParseError r
     skipWhilePartial k s0 =
         let go s = \ inp ->
                 if V.null inp
@@ -699,8 +695,8 @@
         else k s want rest)
   where
     {-# INLINABLE takeTillPartial #-}
-    takeTillPartial :: forall r. (State# ParserState -> V.PrimVector Word8 -> ParseStep r)
-                    -> State# ParserState -> V.PrimVector Word8 -> ParseStep r
+    takeTillPartial :: forall r. (State# ParserState -> V.PrimVector Word8 -> ParseStep ParseError r)
+                    -> State# ParserState -> V.PrimVector Word8 -> ParseStep ParseError r
     takeTillPartial k s0 want =
         let go acc s = \ inp ->
                 if V.null inp
@@ -726,8 +722,8 @@
   where
     -- we want to inline p if possible
     {-# INLINABLE takeWhilePartial #-}
-    takeWhilePartial :: forall r. (State# ParserState -> V.PrimVector Word8 -> ParseStep r)
-                     -> State# ParserState -> V.PrimVector Word8 -> ParseStep r
+    takeWhilePartial :: forall r. (State# ParserState -> V.PrimVector Word8 -> ParseStep ParseError r)
+                     -> State# ParserState -> V.PrimVector Word8 -> ParseStep ParseError r
     takeWhilePartial k s0 want =
         let go acc s = \ inp ->
                 if V.null inp
@@ -759,8 +755,8 @@
 takeRemaining = Parser (\ _ k s inp -> Partial (takeRemainingPartial k s inp))
   where
     {-# INLINABLE takeRemainingPartial #-}
-    takeRemainingPartial :: forall r. (State# ParserState -> V.PrimVector Word8 -> ParseStep r)
-                         -> State# ParserState -> V.PrimVector Word8 -> ParseStep r
+    takeRemainingPartial :: forall r. (State# ParserState -> V.PrimVector Word8 -> ParseStep ParseError r)
+                         -> State# ParserState -> V.PrimVector Word8 -> ParseStep ParseError r
     takeRemainingPartial k s0 want =
         let go acc s = \ inp ->
                 if V.null inp
