diff --git a/library/Text/Builder.hs b/library/Text/Builder.hs
--- a/library/Text/Builder.hs
+++ b/library/Text/Builder.hs
@@ -7,12 +7,14 @@
   char,
   text,
   string,
+  unicodeCodePoint,
   utf16CodeUnits1,
   utf16CodeUnits2,
   utf8CodeUnits1,
   utf8CodeUnits2,
   utf8CodeUnits3,
   utf8CodeUnits4,
+  integral,
 )
 where
 
@@ -110,6 +112,26 @@
 string :: String -> Builder
 string =
   foldMap char
+
+{-# INLINABLE integral #-}
+integral :: Integral a => a -> Builder
+integral =
+  \case
+    0 ->
+      unicodeCodePoint 48
+    x ->
+      bool ((<>) (unicodeCodePoint 45)) id (x >= 0) $
+      loop mempty $
+      abs x
+  where
+    loop builder remainder =
+      case remainder of
+        0 ->
+          builder
+        _ ->
+          case quotRem remainder 10 of
+            (quot, rem) ->
+              loop (unicodeCodePoint (48 + fromIntegral rem) <> builder) quot
 
 {-# INLINE length #-}
 length :: Builder -> Int
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -27,4 +27,7 @@
     \texts ->
       mconcat texts ===
       B.run (mconcat (map B.text texts))
+    ,
+    testCase "Integral" $
+    assertEqual "" "123" (B.run (B.integral 123))
   ]
diff --git a/text-builder.cabal b/text-builder.cabal
--- a/text-builder.cabal
+++ b/text-builder.cabal
@@ -1,7 +1,7 @@
 name:
   text-builder
 version:
-  0.4.2
+  0.4.3
 category:
   Text
 synopsis:
