diff --git a/bench/Bench.hs b/bench/Bench.hs
--- a/bench/Bench.hs
+++ b/bench/Bench.hs
@@ -1,8 +1,10 @@
+{-# options_ghc -Wno-unused-imports #-}
 
 module Main where
 
 import Data.Primitive.ByteArray
 import Gauge
+
 import qualified Data.ByteString.Char8 as B
 
 import qualified Attoparsec
@@ -11,6 +13,7 @@
 import qualified FPStateful
 import qualified FPBasic
 import qualified Bytesmith
+import qualified ReadInteger
 
 sexpInp :: B.ByteString
 sexpInp =
@@ -31,6 +34,9 @@
 numcsvInp' :: ByteArray
 numcsvInp' = Bytesmith.strToByteArray $ B.unpack numcsvInp
 
+readIntInp :: B.ByteString
+readIntInp = "12345678910"
+
 main :: IO ()
 main = defaultMain [
   bgroup "sexp" [
@@ -58,5 +64,10 @@
     bench "attoparsec" $ whnf Attoparsec.runNumcsv numcsvInp,
     bench "megaparsec" $ whnf Megaparsec.runNumcsv numcsvInp,
     bench "parsec"     $ whnf Parsec.runNumcsv     numcsvInp
-  ]
+  ],
+
+  bgroup "readInt/readInteger" [
+    bench "readInt"      $ whnf ReadInteger.readInt     readIntInp,
+    bench "readInteger"  $ whnf ReadInteger.readInteger readIntInp
+    ]
  ]
diff --git a/bench/ReadInteger.hs b/bench/ReadInteger.hs
new file mode 100644
--- /dev/null
+++ b/bench/ReadInteger.hs
@@ -0,0 +1,7 @@
+
+module ReadInteger where
+
+import FlatParse.Basic as FPBasic
+
+readInt     = runParser FPBasic.readInt
+readInteger = runParser FPBasic.readInteger
diff --git a/flatparse.cabal b/flatparse.cabal
--- a/flatparse.cabal
+++ b/flatparse.cabal
@@ -3,11 +3,9 @@
 -- This file has been generated from package.yaml by hpack version 0.34.4.
 --
 -- see: https://github.com/sol/hpack
---
--- hash: 2ba3a084128297d0d1b6136ac0a6aff88c0a67a3998844684ae951a9e56aa339
 
 name:           flatparse
-version:        0.2.1.0
+version:        0.2.2.0
 synopsis:       High-performance parsing from strict bytestrings
 description:    @Flatparse@ is a high-performance parsing library, focusing on programming languages and
                 human-readable data formats. See the README for more information:
@@ -20,9 +18,9 @@
 copyright:      2021 András Kovács
 license:        MIT
 license-file:   LICENSE
+build-type:     Simple
 tested-with:
     GHC == 8.8.4
-build-type:     Simple
 extra-source-files:
     README.md
 
@@ -35,6 +33,7 @@
       FlatParse.Basic
       FlatParse.Examples.BasicLambda.Lexer
       FlatParse.Examples.BasicLambda.Parser
+      FlatParse.Internal
       FlatParse.Stateful
   other-modules:
       Paths_flatparse
@@ -56,6 +55,7 @@
       base >=4.7 && <5
     , bytestring
     , containers
+    , integer-gmp
     , template-haskell
   default-language: Haskell2010
 
@@ -69,6 +69,7 @@
       FPStateful
       Megaparsec
       Parsec
+      ReadInteger
       Paths_flatparse
   hs-source-dirs:
       bench
@@ -91,6 +92,7 @@
     , bytestring
     , flatparse
     , gauge
+    , integer-gmp
     , megaparsec
     , parsec
     , primitive
diff --git a/src/FlatParse/Basic.hs b/src/FlatParse/Basic.hs
--- a/src/FlatParse/Basic.hs
+++ b/src/FlatParse/Basic.hs
@@ -54,6 +54,8 @@
   , isDigit
   , isGreekLetter
   , isLatinLetter
+  , readInt
+  , readInteger
 
   -- * Combinators
   , (<|>)
@@ -127,6 +129,7 @@
 import qualified Data.ByteString.Internal as B
 import qualified Data.Map.Strict as M
 
+import qualified FlatParse.Internal as Internal
 
 --------------------------------------------------------------------------------
 
@@ -603,6 +606,20 @@
 isGreekLetter c = ('Α' <= c && c <= 'Ω') || ('α' <= c && c <= 'ω')
 {-# inline isGreekLetter #-}
 
+-- | Read an `Int` from the input, as a non-empty digit sequence. The `Int` may
+--   overflow in the result.
+readInt :: Parser e Int
+readInt = Parser \fp eob s -> case Internal.readInt eob s of
+  (# (##) | #)        -> Fail#
+  (# | (# n, s' #) #) -> OK# (I# n) s'
+{-# inline readInt #-}
+
+-- | Read an `Integer` from the input, as a non-empty digit sequence.
+readInteger :: Parser e Integer
+readInteger = Parser \fp eob s -> case Internal.readInteger fp eob s of
+  (# (##) | #)        -> Fail#
+  (# | (# i, s' #) #) -> OK# i s'
+{-# inline readInteger #-}
 
 --------------------------------------------------------------------------------
 
diff --git a/src/FlatParse/Examples/BasicLambda/Parser.hs b/src/FlatParse/Examples/BasicLambda/Parser.hs
--- a/src/FlatParse/Examples/BasicLambda/Parser.hs
+++ b/src/FlatParse/Examples/BasicLambda/Parser.hs
@@ -59,7 +59,6 @@
 digit = (\c -> ord c - ord '0') <$> satisfyASCII isDigit
 
 int :: Parser Int
-
 int = token do
   (place, n) <- chainr (\n (!place, !acc) -> (place*10,acc+place*n)) digit (pure (1, 0))
   case place of
@@ -91,7 +90,7 @@
 add' :: Parser Tm
 add' = chainl Add mul' ($(symbol "+") *> mul')
 
--- | Parse an `Eq` or `Lt`-level expression.
+-- | Parse an `FlatParse.Examples.BasicLambda.Parser.Eq` or `Lt`-level expression.
 eqLt' :: Parser Tm
 eqLt' =
   add' >>= \e1 ->
diff --git a/src/FlatParse/Internal.hs b/src/FlatParse/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/FlatParse/Internal.hs
@@ -0,0 +1,42 @@
+
+
+module FlatParse.Internal (readInt, readInteger) where
+
+import qualified Data.ByteString.Char8 as B
+import qualified Data.ByteString.Internal as B
+
+import GHC.Exts
+import GHC.ForeignPtr
+import GHC.Integer.GMP.Internals (Integer(..))
+
+mul10 :: Int# -> Int#
+mul10 n = uncheckedIShiftL# n 3# +# uncheckedIShiftL# n 1#
+{-# inline mul10 #-}
+
+readInt' :: Int# -> Addr# -> Addr# -> (# Int#, Addr# #)
+readInt' acc s end = case eqAddr# s end of
+  1# -> (# acc, s #)
+  _  -> case indexWord8OffAddr# s 0# of
+    w | 1# <- leWord# 48## w, 1# <- leWord# w 57## ->
+      readInt' (mul10 acc +# (word2Int# w -# 48#)) (plusAddr# s 1#) end
+    _ -> (# acc, s #)
+
+
+-- | Read an `Int` from the input, as a non-empty digit sequence. The `Int` may
+--   overflow in the result.
+readInt :: Addr# -> Addr# -> (# (##) | (# Int#, Addr# #) #)
+readInt eob s = case readInt' 0# s eob of
+  (# n, s' #) | 1# <- eqAddr# s s' -> (# (##) | #)
+              | otherwise          -> (# | (# n, s' #) #)
+{-# inline readInt #-}
+
+-- | Read an `Integer` from the input, as a non-empty digit sequence.
+readInteger :: ForeignPtrContents -> Addr# -> Addr# -> (# (##) | (# Integer, Addr# #) #)
+readInteger fp eob s = case readInt' 0# s eob of
+  (# n, s' #)
+    | 1# <- eqAddr# s s'            -> (# (##) | #)
+    | 1# <- minusAddr# s' s <=# 18# -> (# | (# S# n, s' #) #)
+    | otherwise -> case B.readInteger (B.PS (ForeignPtr s fp) 0 (I# (minusAddr# s' s))) of
+        Nothing     -> (# (##) | #)
+        Just (i, _) -> (# | (# i, s' #) #)
+{-# inline readInteger #-}
diff --git a/src/FlatParse/Stateful.hs b/src/FlatParse/Stateful.hs
--- a/src/FlatParse/Stateful.hs
+++ b/src/FlatParse/Stateful.hs
@@ -60,6 +60,8 @@
   , isDigit
   , isGreekLetter
   , isLatinLetter
+  , readInt
+  , readInteger
 
   -- * Combinators
   , (<|>)
@@ -134,6 +136,8 @@
 import qualified Data.ByteString.Unsafe as B
 import qualified Data.Map.Strict as M
 
+import qualified FlatParse.Internal as Internal
+
 --------------------------------------------------------------------------------
 
 -- | Primitive result of a parser. Possible results are given by `OK#`, `Err#` and `Fail#`
@@ -637,6 +641,21 @@
 isGreekLetter :: Char -> Bool
 isGreekLetter c = ('Α' <= c && c <= 'Ω') || ('α' <= c && c <= 'ω')
 {-# inline isGreekLetter #-}
+
+-- | Read an `Int` from the input, as a non-empty digit sequence. The `Int` may
+--   overflow in the result.
+readInt :: Parser e Int
+readInt = Parser \fp r eob s n -> case Internal.readInt eob s of
+  (# (##) | #)        -> Fail#
+  (# | (# i, s' #) #) -> OK# (I# i) s' n
+{-# inline readInt #-}
+
+-- | Read an `Integer` from the input, as a non-empty digit sequence.
+readInteger :: Parser e Integer
+readInteger = Parser \fp r eob s n -> case Internal.readInteger fp eob s of
+  (# (##) | #)        -> Fail#
+  (# | (# i, s' #) #) -> OK# i s' n
+{-# inline readInteger #-}
 
 
 --------------------------------------------------------------------------------
