diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Revision history for array-builder
 
+## 0.2.0.0 -- 2025-09-08
+
+* Rename `Data.Builder.Catenable.Text` to `Data.Builder.Catenable.ShortText`
+* Add `Data.Builder.Catenable.Text` that uses the `Text` type.
+
 ## 0.1.4.1 -- 2024-02-01
 
 * Update package metadata.
diff --git a/array-builder.cabal b/array-builder.cabal
--- a/array-builder.cabal
+++ b/array-builder.cabal
@@ -1,6 +1,6 @@
 cabal-version:   2.2
 name:            array-builder
-version:         0.1.4.1
+version:         0.2.0.0
 synopsis:        Builders for arrays
 description:     Builders for arrays.
 homepage:        https://github.com/byteverse/array-builder
@@ -12,16 +12,23 @@
 copyright:       2019 Andrew Martin
 category:        Data
 extra-doc-files: CHANGELOG.md
+tested-with:     GHC ==9.4.8 || ==9.6.3 || ==9.8.1
 
+common build-settings
+  default-language: Haskell2010
+  ghc-options:      -Wall -Wunused-packages
+
 library
+  import:          build-settings
   exposed-modules:
     Data.Builder
     Data.Builder.Catenable
     Data.Builder.Catenable.Bytes
+    Data.Builder.Catenable.ShortText
     Data.Builder.Catenable.Text
     Data.Builder.ST
 
-  other-modules:    Compat
+  other-modules:   Compat
   build-depends:
     , array-chunks        >=0.1    && <0.2
     , base                >=4.12   && <5
@@ -30,10 +37,10 @@
     , bytestring          >=0.11.5 && <0.12
     , natural-arithmetic  >=0.1.3  && <0.3
     , primitive           >=0.6.4  && <0.10
-    , run-st              >=0.1    && <0.2
     , text-short          >=0.1.3  && <0.2
+    , text                >=2.1
 
-  hs-source-dirs:   src
+  hs-source-dirs:  src
 
   if impl(ghc >=8.9)
     hs-source-dirs: src-post-8.9
@@ -41,21 +48,18 @@
   else
     hs-source-dirs: src-pre-8.9
 
-  default-language: Haskell2010
-  ghc-options:      -Wall -O2
+  ghc-options:     -O2
 
 test-suite test
-  type:             exitcode-stdio-1.0
-  hs-source-dirs:   test
-  main-is:          Main.hs
+  import:         build-settings
+  type:           exitcode-stdio-1.0
+  hs-source-dirs: test
+  main-is:        Main.hs
   build-depends:
     , array-builder
     , base
     , tasty
     , tasty-hunit
-
-  ghc-options:      -Wall -O2
-  default-language: Haskell2010
 
 source-repository head
   type:     git
diff --git a/src/Data/Builder/Catenable.hs b/src/Data/Builder/Catenable.hs
--- a/src/Data/Builder/Catenable.hs
+++ b/src/Data/Builder/Catenable.hs
@@ -1,5 +1,8 @@
 {-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE DerivingStrategies #-}
 {-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE TypeFamilies #-}
 
 {- | Builder with cheap concatenation. Like the builder type from
@@ -62,6 +65,8 @@
   | Cons a !(Builder a)
   | Snoc !(Builder a) a
   | Append !(Builder a) !(Builder a)
+
+deriving stock instance Functor Builder
 
 instance Monoid (Builder a) where
   {-# INLINE mempty #-}
diff --git a/src/Data/Builder/Catenable/ShortText.hs b/src/Data/Builder/Catenable/ShortText.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Builder/Catenable/ShortText.hs
@@ -0,0 +1,138 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE PatternSynonyms #-}
+
+-- | @Data.Builder.Catenable@ specialized to @ShortText@.
+module Data.Builder.Catenable.ShortText
+  ( -- * Type
+    Builder (..)
+
+    -- * Convenient infix operators
+  , pattern (:<)
+  , pattern (:>)
+
+    -- * Run
+  , run
+
+    -- * Properties
+  , length
+
+    -- * Create
+  , shortText
+  , char
+  , word32Dec
+  , word64Dec
+  , int32Dec
+  , int64Dec
+  ) where
+
+import Prelude hiding (length)
+
+import Control.Monad.ST (ST, runST)
+import Data.ByteString.Short.Internal (ShortByteString (SBS))
+import Data.Bytes.Chunks (Chunks (ChunksNil))
+import Data.Int (Int32, Int64)
+import Data.Primitive (ByteArray (ByteArray))
+import Data.String (IsString (fromString))
+import Data.Text.Short (ShortText)
+import Data.Word (Word32, Word64)
+
+import qualified Arithmetic.Nat as Nat
+import qualified Data.Bytes.Builder as BB
+import qualified Data.Bytes.Builder.Bounded as Bounded
+import qualified Data.Bytes.Builder.Unsafe as BBU
+import qualified Data.Bytes.Chunks as Chunks
+import qualified Data.Text.Short as TS
+import qualified Data.Text.Short.Unsafe as TS
+
+infixr 5 :<
+infixl 5 :>
+
+data Builder
+  = Empty
+  | Cons !ShortText !Builder
+  | Snoc !Builder !ShortText
+  | Append !Builder !Builder
+
+shortText :: ShortText -> Builder
+shortText !t = Cons t Empty
+
+char :: Char -> Builder
+char !c = Cons (TS.singleton c) Empty
+
+word32Dec :: Word32 -> Builder
+word32Dec !i = Cons (ba2st (Bounded.run Nat.constant (Bounded.word32Dec i))) Empty
+
+word64Dec :: Word64 -> Builder
+word64Dec !i = Cons (ba2st (Bounded.run Nat.constant (Bounded.word64Dec i))) Empty
+
+int32Dec :: Int32 -> Builder
+int32Dec !i = Cons (ba2st (Bounded.run Nat.constant (Bounded.int32Dec i))) Empty
+
+int64Dec :: Int64 -> Builder
+int64Dec !i = Cons (ba2st (Bounded.run Nat.constant (Bounded.int64Dec i))) Empty
+
+-- | Number of Unicode code points in the sequence.
+length :: Builder -> Int
+length b0 = case b0 of
+  Empty -> 0
+  Cons x b1 -> TS.length x + length b1
+  Snoc b1 x -> TS.length x + length b1
+  Append x y -> length x + length y
+
+{- | Note: The choice of appending to the left side of @Empty@ instead
+of the right side of arbitrary. Under ordinary use, this difference
+cannot be observed by the user.
+-}
+instance IsString Builder where
+  fromString t = Cons (TS.pack t) Empty
+
+instance Monoid Builder where
+  {-# INLINE mempty #-}
+  mempty = Empty
+
+instance Semigroup Builder where
+  {-# INLINE (<>) #-}
+  (<>) = Append
+
+{- | Not structural equality. Converts builders to chunks and then
+compares the chunks.
+-}
+instance Eq Builder where
+  a == b = run a == run b
+
+instance Show Builder where
+  show b = TS.unpack (ba2st (Chunks.concatU (run b)))
+
+ba2st :: ByteArray -> ShortText
+{-# INLINE ba2st #-}
+ba2st (ByteArray x) = TS.fromShortByteStringUnsafe (SBS x)
+
+pattern (:<) :: ShortText -> Builder -> Builder
+pattern (:<) x y = Cons x y
+
+pattern (:>) :: Builder -> ShortText -> Builder
+pattern (:>) x y = Snoc x y
+
+{- | The result is chunks, but this is guaranteed to be UTF-8 encoded
+text, so if needed, you can flatten out the chunks and convert back
+to @ShortText@.
+-}
+run :: Builder -> Chunks
+{-# NOINLINE run #-}
+run b = runST $ do
+  bldr0 <- BBU.newBuilderState 128
+  bldr1 <- pushCatenable bldr0 b
+  BBU.reverseCommitsOntoChunks ChunksNil (BBU.closeBuilderState bldr1)
+
+pushCatenable :: BBU.BuilderState s -> Builder -> ST s (BBU.BuilderState s)
+pushCatenable !bldr0 b = case b of
+  Empty -> pure bldr0
+  Cons x b1 -> do
+    bldr1 <- BBU.pasteST (BB.shortTextUtf8 x) bldr0
+    pushCatenable bldr1 b1
+  Snoc b1 x -> do
+    bldr1 <- pushCatenable bldr0 b1
+    BBU.pasteST (BB.shortTextUtf8 x) bldr1
+  Append x y -> do
+    bldr1 <- pushCatenable bldr0 x
+    pushCatenable bldr1 y
diff --git a/src/Data/Builder/Catenable/Text.hs b/src/Data/Builder/Catenable/Text.hs
--- a/src/Data/Builder/Catenable/Text.hs
+++ b/src/Data/Builder/Catenable/Text.hs
@@ -18,6 +18,7 @@
 
     -- * Create
   , shortText
+  , text
   , char
   , word32Dec
   , word64Dec
@@ -33,6 +34,7 @@
 import Data.Int (Int32, Int64)
 import Data.Primitive (ByteArray (ByteArray))
 import Data.String (IsString (fromString))
+import Data.Text (Text)
 import Data.Text.Short (ShortText)
 import Data.Word (Word32, Word64)
 
@@ -41,6 +43,7 @@
 import qualified Data.Bytes.Builder.Bounded as Bounded
 import qualified Data.Bytes.Builder.Unsafe as BBU
 import qualified Data.Bytes.Chunks as Chunks
+import qualified Data.Text as T
 import qualified Data.Text.Short as TS
 import qualified Data.Text.Short.Unsafe as TS
 
@@ -49,34 +52,37 @@
 
 data Builder
   = Empty
-  | Cons !ShortText !Builder
-  | Snoc !Builder !ShortText
+  | Cons !Text !Builder
+  | Snoc !Builder !Text
   | Append !Builder !Builder
 
 shortText :: ShortText -> Builder
-shortText !t = Cons t Empty
+shortText !t = Cons (TS.toText t) Empty
 
+text :: Text -> Builder
+text !t = Cons t Empty
+
 char :: Char -> Builder
-char !c = Cons (TS.singleton c) Empty
+char !c = Cons (T.singleton c) Empty
 
 word32Dec :: Word32 -> Builder
-word32Dec !i = Cons (ba2st (Bounded.run Nat.constant (Bounded.word32Dec i))) Empty
+word32Dec !i = Cons (TS.toText (ba2st (Bounded.run Nat.constant (Bounded.word32Dec i)))) Empty
 
 word64Dec :: Word64 -> Builder
-word64Dec !i = Cons (ba2st (Bounded.run Nat.constant (Bounded.word64Dec i))) Empty
+word64Dec !i = Cons (TS.toText (ba2st (Bounded.run Nat.constant (Bounded.word64Dec i)))) Empty
 
 int32Dec :: Int32 -> Builder
-int32Dec !i = Cons (ba2st (Bounded.run Nat.constant (Bounded.int32Dec i))) Empty
+int32Dec !i = Cons (TS.toText (ba2st (Bounded.run Nat.constant (Bounded.int32Dec i)))) Empty
 
 int64Dec :: Int64 -> Builder
-int64Dec !i = Cons (ba2st (Bounded.run Nat.constant (Bounded.int64Dec i))) Empty
+int64Dec !i = Cons (TS.toText (ba2st (Bounded.run Nat.constant (Bounded.int64Dec i)))) Empty
 
 -- | Number of Unicode code points in the sequence.
 length :: Builder -> Int
 length b0 = case b0 of
   Empty -> 0
-  Cons x b1 -> TS.length x + length b1
-  Snoc b1 x -> TS.length x + length b1
+  Cons x b1 -> T.length x + length b1
+  Snoc b1 x -> T.length x + length b1
   Append x y -> length x + length y
 
 {- | Note: The choice of appending to the left side of @Empty@ instead
@@ -84,7 +90,7 @@
 cannot be observed by the user.
 -}
 instance IsString Builder where
-  fromString t = Cons (TS.pack t) Empty
+  fromString t = Cons (T.pack t) Empty
 
 instance Monoid Builder where
   {-# INLINE mempty #-}
@@ -107,10 +113,10 @@
 {-# INLINE ba2st #-}
 ba2st (ByteArray x) = TS.fromShortByteStringUnsafe (SBS x)
 
-pattern (:<) :: ShortText -> Builder -> Builder
+pattern (:<) :: Text -> Builder -> Builder
 pattern (:<) x y = Cons x y
 
-pattern (:>) :: Builder -> ShortText -> Builder
+pattern (:>) :: Builder -> Text -> Builder
 pattern (:>) x y = Snoc x y
 
 {- | The result is chunks, but this is guaranteed to be UTF-8 encoded
@@ -128,11 +134,11 @@
 pushCatenable !bldr0 b = case b of
   Empty -> pure bldr0
   Cons x b1 -> do
-    bldr1 <- BBU.pasteST (BB.shortTextUtf8 x) bldr0
+    bldr1 <- BBU.pasteST (BB.textUtf8 x) bldr0
     pushCatenable bldr1 b1
   Snoc b1 x -> do
     bldr1 <- pushCatenable bldr0 b1
-    BBU.pasteST (BB.shortTextUtf8 x) bldr1
+    BBU.pasteST (BB.textUtf8 x) bldr1
   Append x y -> do
     bldr1 <- pushCatenable bldr0 x
     pushCatenable bldr1 y
